import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import "../../styles/ptw-form-fill-hub.css";
import "../../styles/ptw-document-form.css";
import { useAuth } from "../../context/AuthContext.jsx";
import PageHeader from "../../components/common/PageHeader.jsx";
import ErrorBanner from "../../components/common/ErrorBanner.jsx";
import PermitEntryWarningModal from "../../components/common/PermitEntryWarningModal.jsx";
import PtwDocumentSection from "../../components/form/PtwDocumentSection.jsx";
import PtwFormDocument from "../../components/form/PtwFormDocument.jsx";
import PtwSectionProgress from "../../components/form/PtwSectionProgress.jsx";
import useMasterData from "../../hooks/useMasterData.js";
import { listForms, loadFormForFill } from "../../services/formsApi.js";
import { formatPermitValidity, usePermitValidity } from "../../context/PermitValidityContext.jsx";
import { usePtwNavigation } from "../../context/PtwNavigationContext.jsx";
import { createPermit, createSubmission, getPermit, listOpeningClosingMap, listSubmissions } from "../../services/permitsApi.js";
import { parseNavFromHash, writeNavHash } from "../../utils/ptwNavUrl.js";
import {
  buildSpecializedFormOptions,
  clearResumeIntent,
  loadPermitHubContext,
  readResumeIntent,
  resolveSpecializedForm,
  storeResumeIntent
} from "../../utils/ptwPermitResume.js";
import {
  findFormForJobType,
  findGeneralJobType,
  resolveJobTypeColor,
  specializedJobTypes
} from "../../utils/jobTypeHelpers.js";
import {
  SECTION_KIND,
  excludeLifecycleSections,
  isSectionSkipable,
  resolveSectionKind,
  sortSections
} from "../../utils/sectionTypeHelpers.js";
import {
  QUESTION_TYPE_KIND,
  getSignoffRoleLabel,
  isAuthorizationQuestionType,
  isDeclarationTextQuestion,
  isImageQuestionType,
  parseSignoffAnswer,
  resolveQuestionTypeKind,
  serializeSignoffAnswer,
  validatePrecautionChecklistNoAnswers,
  validateSignoffAnswer
} from "../../utils/questionTypeHelpers.js";
import {
  findPermitVideoSectionId,
  formRequiresPermitVideo,
  getStoredPermitVideo,
  setStoredPermitVideo,
  clearStoredPermitVideo
} from "../../utils/permitVideoHelpers.js";
import {
  collectRiskAssessmentDisplayQuestions,
  countEmptyRiskAssessmentCells,
  RISK_ASSESSMENT_INITIAL_ROWS,
  parseRiskAssessmentQuestions,
  resolveRiskVisibleRowCount,
  shouldUseRiskAssessmentSectionLayout,
  trimRiskAnswersForVisibleRows
} from "../../utils/riskAssessmentHelpers.js";
import { validateUploadSize } from "../../utils/uploadLimits.js";
import { downloadGeneralPtwExcel } from "../../utils/generalPtwExcelExport.js";

function sectionCacheKey(sectionId) {
  return String(sectionId);
}

function readAnswerValue(answers, questionId) {
  return answers[questionId] ?? answers[String(questionId)] ?? "";
}

function readMediaFiles(mediaByQuestion, questionId) {
  return mediaByQuestion[questionId] || mediaByQuestion[String(questionId)] || [];
}

function validateSectionVideoFiles(files, label = "Video") {
  for (const file of files || []) {
    const err = validateUploadSize(file, label);
    if (err) return err;
  }
  return null;
}

function handleVideoUpload(setter) {
  return (file) => {
    if (file) {
      const err = validateUploadSize(file, "Video");
      if (err) {
        setter([]);
        return err;
      }
      setter([file]);
      return null;
    }
    setter([]);
    return null;
  };
}

function typeOptionsForQuestion(question, questionTypeOptions) {
  if (question?.question_type) {
    return [
      {
        value: String(question.question_type_id ?? ""),
        label: question.question_type
      }
    ];
  }
  return questionTypeOptions;
}

function isAnswerEmpty(question, answerValue, mediaFiles, questionTypeOptions) {
  const typeOpts = typeOptionsForQuestion(question, questionTypeOptions);
  const kind = resolveQuestionTypeKind(
    question.question_type_id,
    typeOpts,
    question.question_type
  );
  const hasMedia = Array.isArray(mediaFiles) && mediaFiles.length > 0;

  if (
    isAuthorizationQuestionType(
      question.question_type_id,
      typeOpts,
      question.question_type
    )
  ) {
    return Boolean(
      validateSignoffAnswer(
        answerValue,
        mediaFiles.filter(Boolean)[0] || null,
        getSignoffRoleLabel(question)
      )
    );
  }

  if (kind === QUESTION_TYPE_KIND.IMAGE || isImageQuestionType(question.question_type_id, typeOpts)) {
    return !hasMedia;
  }

  return !String(answerValue ?? "").trim() && !hasMedia;
}

function buildQuestionAnswers(questions, answers, mediaByQuestion, questionTypeOptions) {
  return (questions || []).map((q) => {
    const qid = q.question_id;
    const files = readMediaFiles(mediaByQuestion, qid).filter(Boolean);
    const typeOpts = typeOptionsForQuestion(q, questionTypeOptions);
    const kind = resolveQuestionTypeKind(
      q.question_type_id,
      typeOpts,
      q.question_type
    );

    if (
      isAuthorizationQuestionType(q.question_type_id, typeOpts, q.question_type)
    ) {
      const raw = readAnswerValue(answers, qid);
      return {
        question_id: qid,
        is_media: files.length > 0 ? 1 : 0,
        answer_value: raw ? serializeSignoffAnswer(parseSignoffAnswer(raw)) : null
      };
    }

    const isMedia =
      files.length > 0 ||
      kind === QUESTION_TYPE_KIND.IMAGE ||
      isImageQuestionType(q.question_type_id, typeOpts)
        ? 1
        : 0;
    let answerValue = readAnswerValue(answers, qid);
    if (isMedia && !String(answerValue).trim() && files.length) {
      answerValue = files.map((f) => f.name).join(", ");
    }
    return {
      question_id: qid,
      is_media: isMedia,
      answer_value: answerValue || null
    };
  });
}

function getAnchorQuestionId(section) {
  const questions = section?.questions || [];
  return questions[0]?.question_id ?? null;
}

function snapshotSectionFields({
  answers,
  mediaByQuestion,
  skipChoice,
  skipReference,
  skipNotes,
  riskVisibleRowCount
}) {
  return {
    answers: { ...answers },
    mediaByQuestion: { ...mediaByQuestion },
    skipChoice: skipChoice || "",
    skipReference: skipReference || "",
    skipNotes: skipNotes || "",
    riskVisibleRowCount: riskVisibleRowCount || RISK_ASSESSMENT_INITIAL_ROWS
  };
}

function buildSectionSubmissionPart(
  section,
  snapshot,
  questionTypeOptions,
  { permitVideo, permitVideoSectionId }
) {
  const sectionId = section.section_id;
  const part = {
    answers: [],
    mediaByQuestion: {},
    sectionMedia: {}
  };

  if (isSectionSkipable(section) && snapshot.skipChoice === "yes") {
    const anchorId = getAnchorQuestionId(section);
    if (anchorId) {
      const skipNotes = [
        `${section.title || "Section"} skipped — already completed elsewhere.`,
        snapshot.skipReference ? `Reference: ${snapshot.skipReference}` : null,
        snapshot.skipNotes ? `Notes: ${snapshot.skipNotes}` : null
      ]
        .filter(Boolean)
        .join(" ");
      part.answers.push({
        question_id: anchorId,
        is_media: 0,
        answer_value: skipNotes
      });
    }
    return part;
  }

  const sectionQuestions = section.questions || [];
  const useRiskLayout = shouldUseRiskAssessmentSectionLayout(
    section,
    sectionQuestions
  );
  if (useRiskLayout) {
    const visibleRows =
      snapshot.riskVisibleRowCount || RISK_ASSESSMENT_INITIAL_ROWS;
    const riskQuestions = collectRiskAssessmentDisplayQuestions(
      sectionQuestions,
      visibleRows
    );
    const riskAnswers = trimRiskAnswersForVisibleRows(
      sectionQuestions,
      snapshot.answers,
      visibleRows
    );
    part.answers = buildQuestionAnswers(
      riskQuestions,
      riskAnswers,
      snapshot.mediaByQuestion,
      questionTypeOptions
    );
  } else {
    part.answers = buildQuestionAnswers(
      sectionQuestions,
      snapshot.answers,
      snapshot.mediaByQuestion,
      questionTypeOptions
    );
  }
  part.mediaByQuestion = { ...snapshot.mediaByQuestion };

  if (
    permitVideo?.length &&
    Number(sectionId) === Number(permitVideoSectionId)
  ) {
    part.sectionMedia[sectionId] = {
      video: [...permitVideo],
      signature: [],
      selfie: []
    };
  }

  return part;
}

function findUncachedSections(orderedSections, sectionCache) {
  return (orderedSections || []).filter(
    (section) => !sectionCache[sectionCacheKey(section.section_id)]
  );
}

function formatMissingSectionsError(missingSections, orderedSections) {
  const labels = missingSections.map((section) => {
    const idx =
      orderedSections.findIndex((s) => s.section_id === section.section_id) + 1;
    const title = section.title || `Section #${section.section_id}`;
    return `section ${idx}: ${title}`;
  });
  return `Complete ${labels.join(" and ")} before submitting.`;
}

function buildFullSubmissionFromCache(
  orderedSections,
  sectionCache,
  questionTypeOptions,
  permitVideo,
  permitVideoSectionId
) {
  const answersByQuestion = new Map();
  const allMediaByQuestion = {};
  const allSectionMedia = {};

  for (const section of orderedSections) {
    const snapshot = sectionCache[sectionCacheKey(section.section_id)];
    if (!snapshot) {
      throw new Error(
        `Section "${section.title || section.section_id}" has not been completed.`
      );
    }
    const part = buildSectionSubmissionPart(section, snapshot, questionTypeOptions, {
      permitVideo,
      permitVideoSectionId
    });
    for (const ans of part.answers) {
      answersByQuestion.set(ans.question_id, ans);
    }
    Object.assign(allMediaByQuestion, part.mediaByQuestion);
    Object.assign(allSectionMedia, part.sectionMedia);
  }

  return {
    answers: Array.from(answersByQuestion.values()),
    mediaByQuestion: allMediaByQuestion,
    sectionMedia: allSectionMedia
  };
}

export default function AdminFormFillPage() {
  const { auth } = useAuth();
  const { setActivePermit } = usePermitValidity();
  const { navigate } = usePtwNavigation() || {};
  const { data, loading: masterLoading, error: masterError } = useMasterData();
  const WORKFLOW = {
    IDLE: "idle",
    GENERAL: "general",
    GENERAL_COMPLETE: "general_complete",
    SPECIALIZED: "specialized",
    ALL_COMPLETE: "all_complete"
  };

  const [forms, setForms] = useState([]);
  const [permitId, setPermitId] = useState("");
  const [permitNumber, setPermitNumber] = useState("");
  const [formId, setFormId] = useState("");
  const [workflowPhase, setWorkflowPhase] = useState(WORKFLOW.IDLE);
  const [generalSubmissionId, setGeneralSubmissionId] = useState(null);
  const [specializedSubmissions, setSpecializedSubmissions] = useState([]);
  const [selectedJobTypeId, setSelectedJobTypeId] = useState("");
  const [formDef, setFormDef] = useState(null);
  const [submissionId, setSubmissionId] = useState(null);
  const [sectionIndex, setSectionIndex] = useState(0);
  const [sectionCache, setSectionCache] = useState({});
  const sectionCacheRef = useRef({});
  const [answers, setAnswers] = useState({});
  const [mediaByQuestion, setMediaByQuestion] = useState({});
  const [permitVideo, setPermitVideo] = useState([]);
  const [skipChoice, setSkipChoice] = useState("");
  const [skipReference, setSkipReference] = useState("");
  const [skipNotes, setSkipNotes] = useState("");
  const [riskVisibleRowCount, setRiskVisibleRowCount] = useState(RISK_ASSESSMENT_INITIAL_ROWS);
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);
  const [loadingForm, setLoadingForm] = useState(false);
  const [submitting, setSubmitting] = useState(false);
  const [formComplete, setFormComplete] = useState(false);
  const [lastSectionResult, setLastSectionResult] = useState(null);
  const [entryWarningOpen, setEntryWarningOpen] = useState(false);
  const [showSpecializedPicker, setShowSpecializedPicker] = useState(false);
  const [exportSnapshot, setExportSnapshot] = useState(null);
  const [exportingExcel, setExportingExcel] = useState(false);
  const stepErrorRef = useRef(null);
  const permitVideoRef = useRef([]);
  const permitVideoInputRef = useRef(null);
  const resumeAttemptedRef = useRef(false);

  const jobTypes = useMemo(
    () => (Array.isArray(data.ptw_job_type) ? data.ptw_job_type : []),
    [data.ptw_job_type]
  );

  const generalJobType = useMemo(() => findGeneralJobType(jobTypes), [jobTypes]);
  const specializedTypes = useMemo(() => specializedJobTypes(jobTypes), [jobTypes]);

  const activeJobTypeId = useMemo(() => {
    if (workflowPhase === WORKFLOW.GENERAL) {
      return generalJobType?.job_type_id;
    }
    if (workflowPhase === WORKFLOW.SPECIALIZED) {
      return selectedJobTypeId;
    }
    return null;
  }, [workflowPhase, generalJobType, selectedJobTypeId]);

  const jobColor = useMemo(
    () => resolveJobTypeColor(jobTypes, activeJobTypeId),
    [jobTypes, activeJobTypeId]
  );

  const specializedFormOptions = useMemo(
    () => buildSpecializedFormOptions(forms, jobTypes),
    [forms, jobTypes]
  );

  const selectedSpecializedForm = useMemo(() => {
    if (!selectedJobTypeId) return null;
    return findFormForJobType(forms, selectedJobTypeId);
  }, [forms, selectedJobTypeId]);

  const isDocumentFullLayout =
    formDef &&
    (workflowPhase === WORKFLOW.GENERAL || workflowPhase === WORKFLOW.SPECIALIZED) &&
    !formComplete;

  const questionTypeOptions = useMemo(
    () =>
      (data.ptw_question_type || []).map((row) => ({
        value: String(row.question_type_id),
        label: row.question_type || `#${row.question_type_id}`
      })),
    [data.ptw_question_type]
  );

  const orderedSections = useMemo(
    () => excludeLifecycleSections(sortSections(formDef?.sections)),
    [formDef]
  );

  const currentSection = orderedSections[sectionIndex] ?? null;
  const sectionKind = currentSection
    ? resolveSectionKind(currentSection)
    : null;
  const sectionSkipable = currentSection ? isSectionSkipable(currentSection) : false;

  const permitVideoCommitted =
    workflowPhase === WORKFLOW.SPECIALIZED || Boolean(generalSubmissionId);

  const loadMeta = useCallback(async () => {
    setLoading(true);
    try {
      setError("");
      const formsList = await listForms();
      setForms(Array.isArray(formsList) ? formsList : []);
    } catch (err) {
      setError(err?.response?.data?.message || err.message);
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    loadMeta();
  }, [loadMeta]);

  function setSectionCacheBoth(next) {
    sectionCacheRef.current = next;
    setSectionCache(next);
  }

  function setPermitVideoBoth(files) {
    const next = setStoredPermitVideo(permitId, files);
    permitVideoRef.current = next;
    setPermitVideo(next);
  }

  function readPermitVideoFromInput() {
    const file = permitVideoInputRef.current?.files?.[0];
    return file ? [file] : [];
  }

  function getPersistedPermitVideo() {
    if (permitVideoRef.current.length) return permitVideoRef.current;
    if (permitVideo.length) return [...permitVideo];
    return getStoredPermitVideo(permitId);
  }

  /** Read permit video from ref, state, session store, or file input (no setState). */
  function readPermitVideoFiles() {
    const persisted = getPersistedPermitVideo();
    if (persisted.length) return persisted;
    return readPermitVideoFromInput();
  }

  /** Persist a selected video file before validation / section navigation. */
  function resolvePermitVideo() {
    const existing = readPermitVideoFiles();
    if (existing.length) {
      if (!permitVideoRef.current.length) {
        setPermitVideoBoth(existing);
      }
      return existing;
    }
    return [];
  }

  function resetSectionFields() {
    setAnswers({});
    setMediaByQuestion({});
    setSkipChoice("");
    setSkipReference("");
    setSkipNotes("");
    setRiskVisibleRowCount(RISK_ASSESSMENT_INITIAL_ROWS);
  }

  function applySectionSnapshot(snapshot, section = null) {
    if (!snapshot) {
      resetSectionFields();
      return;
    }
    setAnswers(snapshot.answers || {});
    setMediaByQuestion(snapshot.mediaByQuestion || {});
    setSkipChoice(snapshot.skipChoice || "");
    setSkipReference(snapshot.skipReference || "");
    setSkipNotes(snapshot.skipNotes || "");

    if (Number.isFinite(snapshot.riskVisibleRowCount) && snapshot.riskVisibleRowCount > 0) {
      setRiskVisibleRowCount(snapshot.riskVisibleRowCount);
      return;
    }

    const questions = section?.questions || [];
    if (
      section &&
      shouldUseRiskAssessmentSectionLayout(section, questions)
    ) {
      const { rows } = parseRiskAssessmentQuestions(questions);
      setRiskVisibleRowCount(
        resolveRiskVisibleRowCount(rows, snapshot.answers || {})
      );
      return;
    }

    setRiskVisibleRowCount(RISK_ASSESSMENT_INITIAL_ROWS);
  }

  function snapshotCurrentSection() {
    return snapshotSectionFields({
      answers,
      mediaByQuestion,
      skipChoice,
      skipReference,
      skipNotes,
      riskVisibleRowCount
    });
  }

  useEffect(() => {
    if (!permitId) return;
    const stored = getStoredPermitVideo(permitId);
    if (stored.length) {
      permitVideoRef.current = stored;
      setPermitVideo(stored);
    }
  }, [permitId]);

  const needsPermitVideo = formRequiresPermitVideo(
    orderedSections,
    sectionCache,
    sectionCacheKey,
    currentSection,
    skipChoice
  );
  const persistedPermitVideo = getPersistedPermitVideo();
  const hasPersistedPermitVideo = permitVideoCommitted || persistedPermitVideo.length > 0;
  const showPermitVideoUpload =
    !permitVideoCommitted &&
    needsPermitVideo &&
    sectionIndex === 0 &&
    !hasPersistedPermitVideo;

  async function loadFormById(fid, phase, { errorPhase = WORKFLOW.IDLE } = {}) {
    setLoadingForm(true);
    setError("");
    setFormComplete(false);
    setLastSectionResult(null);
    setSubmissionId(null);
    setSectionIndex(0);
    setSectionCacheBoth({});
    resetSectionFields();
    setFormId(String(fid));
    setWorkflowPhase(phase);
    try {
      const loaded = await loadFormForFill(fid);
      setFormDef(loaded);
      return loaded;
    } catch (err) {
      setError(err?.response?.data?.message || err.message);
      setFormDef(null);
      setWorkflowPhase(errorPhase);
      return null;
    } finally {
      setLoadingForm(false);
    }
  }

  function applyPermitHubState(hub) {
    setPermitId(hub.permitId);
    setPermitNumber(hub.permitNumber);
    setGeneralSubmissionId(hub.generalSubmissionId);
    setSpecializedSubmissions(hub.specializedSubmissions);
    setLastSectionResult({
      valid_from: hub.validFrom,
      valid_until: hub.validUntil
    });
    setActivePermit({
      permitId: Number(hub.permitId),
      permitNumber: hub.permitNumber,
      validFrom: hub.validFrom,
      validUntil: hub.validUntil
    });
  }

  useEffect(() => {
    if (resumeAttemptedRef.current) return;
    if (masterLoading || loading) return;
    if (!forms.length || !jobTypes.length) return;

    const hashParams = parseNavFromHash().params;
    const storedIntent = readResumeIntent();
    const resumeId = hashParams.permitId || storedIntent?.permitId;
    const pendingJobTypeId = hashParams.jobTypeId || storedIntent?.jobTypeId;
    if (!resumeId) return;

    resumeAttemptedRef.current = true;
    let cancelled = false;
    setLoadingForm(true);

    (async () => {
      try {
        setError("");
        const hub = await loadPermitHubContext(resumeId, {
          forms,
          jobTypes,
          getPermit,
          listSubmissions,
          listOpeningClosingMap
        });
        if (cancelled) return;

        applyPermitHubState(hub);

        if (pendingJobTypeId) {
          const specializedForm = resolveSpecializedForm(forms, pendingJobTypeId);
          if (specializedForm) {
            setSelectedJobTypeId(String(pendingJobTypeId));
            const loaded = await loadFormById(specializedForm.form_id, WORKFLOW.SPECIALIZED, {
              errorPhase: WORKFLOW.GENERAL_COMPLETE
            });
            if (cancelled) return;
            if (loaded) {
              clearResumeIntent();
              writeNavHash("fill-form", {}, { replace: true });
            }
            return;
          }
          setWorkflowPhase(WORKFLOW.GENERAL_COMPLETE);
          setShowSpecializedPicker(true);
          setError("Selected specialized form is no longer available. Pick another form.");
          setLoadingForm(false);
          return;
        }

        setWorkflowPhase(WORKFLOW.GENERAL_COMPLETE);
        clearResumeIntent();
        writeNavHash("fill-form", {}, { replace: true });
        setLoadingForm(false);
      } catch (err) {
        if (cancelled) return;
        resumeAttemptedRef.current = false;
        setError(err?.response?.data?.message || err.message);
        setLoadingForm(false);
      }
    })();

    return () => {
      cancelled = true;
      resumeAttemptedRef.current = false;
    };
  }, [forms, jobTypes, loading, masterLoading, setActivePermit]);

  function handleRequestStartPtw() {
    if (!generalJobType) {
      setError(
        'No GENERAL job type found in ptw_job_type (expected job_type_id 1). Run ptw_backend/sql/migrations/seed_ptw_job_type.sql against the hse database, then refresh this page.'
      );
      return;
    }
    const generalForm = findFormForJobType(forms, generalJobType.job_type_id);
    if (!generalForm) {
      setError(
        `No form is linked to ${generalJobType.job_type_name} (job_type_id ${generalJobType.job_type_id}) in ptw_form_details. Set job_type_id on a form in Form Management.`
      );
      return;
    }

    setError("");
    setEntryWarningOpen(true);
  }

  async function handleConfirmStartPtw() {
    const generalForm = findFormForJobType(forms, generalJobType.job_type_id);
    if (!generalForm) {
      setEntryWarningOpen(false);
      return;
    }

    setLoadingForm(true);
    setError("");
    setGeneralSubmissionId(null);
    setSelectedJobTypeId("");
    setPermitId("");
    setPermitNumber("");
    setExportSnapshot(null);
    try {
      const created = await createPermit({ permit_status_id: 1 });
      const pid = created?.insertedId ?? created?.permit_id;
      if (!pid) throw new Error("Failed to create permit.");
      setPermitId(String(pid));
      setPermitNumber(created?.permit_number || `PTW-${pid}`);
      await loadFormById(generalForm.form_id, WORKFLOW.GENERAL);
      setEntryWarningOpen(false);
    } catch (err) {
      setError(err?.response?.data?.message || err.message);
      setLoadingForm(false);
    }
  }

  async function handleStartSpecialized() {
    const jtid = Number(selectedJobTypeId);
    if (!Number.isFinite(jtid) || jtid <= 0) {
      setError("Select a specialized permit type to continue.");
      return;
    }
    const specializedForm = findFormForJobType(forms, jtid);
    if (!specializedForm) {
      const jt = specializedTypes.find((t) => Number(t.job_type_id) === jtid);
      setError(
        `No form is linked to "${jt?.job_type_name || "this job type"}". Configure a form in Form Management.`
      );
      return;
    }

    setLoadingForm(true);
    setError("");
    try {
      await loadFormById(specializedForm.form_id, WORKFLOW.SPECIALIZED, {
        errorPhase: WORKFLOW.GENERAL_COMPLETE
      });
    } catch (err) {
      setError(err?.response?.data?.message || err.message);
      setLoadingForm(false);
    }
  }

  function handleGoToPermitsList() {
    if (permitId) {
      storeResumeIntent({ permitId });
      if (lastSectionResult?.valid_from && lastSectionResult?.valid_until) {
        setActivePermit({
          permitId: Number(permitId),
          permitNumber,
          validFrom: lastSectionResult.valid_from,
          validUntil: lastSectionResult.valid_until
        });
      } else if (permitNumber) {
        setActivePermit({
          permitId: Number(permitId),
          permitNumber,
          validFrom: null,
          validUntil: null
        });
      }
    }
    navigate?.("permits-submissions");
  }

  function handleAddSpecializedForm() {
    if (!specializedFormOptions.some((opt) => opt.form)) return;
    if (showSpecializedPicker) {
      handleStartSpecialized();
      return;
    }
    setError("");
    setShowSpecializedPicker(true);
  }

  function handleStartAnother() {
    const previousPermitId = permitId;
    resumeAttemptedRef.current = false;
    clearResumeIntent();
    setWorkflowPhase(WORKFLOW.IDLE);
    setFormDef(null);
    setFormComplete(false);
    setSubmissionId(null);
    setGeneralSubmissionId(null);
    setSpecializedSubmissions([]);
    setPermitId("");
    setPermitNumber("");
    setFormId("");
    setSelectedJobTypeId("");
    setShowSpecializedPicker(false);
    setSectionIndex(0);
    setSectionCacheBoth({});
    resetSectionFields();
    clearStoredPermitVideo(previousPermitId);
    permitVideoRef.current = [];
    setPermitVideo([]);
    if (permitVideoInputRef.current) {
      permitVideoInputRef.current.value = "";
    }
  }

  function setAnswer(questionId, value) {
    setAnswers((prev) => ({
      ...prev,
      [questionId]: typeof value === "function" ? value(prev) : value
    }));
  }

  function setMedia(questionId, files) {
    setMediaByQuestion((prev) => ({ ...prev, [questionId]: files }));
  }

  function validateCurrentSection() {
    if (!currentSection) return "No section loaded.";

    if (sectionSkipable && !skipChoice) {
      return "Indicate whether this section can be skipped.";
    }

    if (
      needsPermitVideo &&
      !permitVideoCommitted &&
      !resolvePermitVideo().length
    ) {
      return sectionIndex === 0
        ? "Upload a permit video before continuing."
        : "Upload a permit video on the first section before continuing.";
    }

    if (needsPermitVideo && !permitVideoCommitted) {
      const videoErr = validateSectionVideoFiles(resolvePermitVideo(), "Permit video");
      if (videoErr) return videoErr;
    }

    if (sectionSkipable && skipChoice === "yes") {
      return null;
    }

    const questions = currentSection.questions || [];
    const useRiskLayout = shouldUseRiskAssessmentSectionLayout(
      currentSection,
      questions
    );

    if (useRiskLayout) {
      const emptyCells = countEmptyRiskAssessmentCells(
        questions,
        answers,
        riskVisibleRowCount
      );
      if (emptyCells > 0) {
        return `Please complete all risk assessment cells (${emptyCells} remaining).`;
      }
    } else {
      const missing = questions.filter((q) => {
        if (isDeclarationTextQuestion(q, questionTypeOptions)) {
          return false;
        }
        return isAnswerEmpty(
          q,
          readAnswerValue(answers, q.question_id),
          readMediaFiles(mediaByQuestion, q.question_id),
          questionTypeOptions
        );
      });

      if (missing.length) {
        return `Please complete all questions in this section (${missing.length} remaining).`;
      }
    }

    if (
      !useRiskLayout &&
      (sectionKind === SECTION_KIND.STANDARD || sectionKind === SECTION_KIND.RISK) &&
      (!sectionSkipable || skipChoice === "no")
    ) {
      const noErr = validatePrecautionChecklistNoAnswers(
        questions,
        answers,
        questionTypeOptions
      );
      if (noErr) return noErr;
    }

    return null;
  }

  function handleSkipChoice(value) {
    setSkipChoice(value);
  }

  function handlePermitVideoUpload(file) {
    const uploadErr = handleVideoUpload(setPermitVideoBoth)(file);
    if (uploadErr) setError(uploadErr);
    else setError("");
  }

  async function handleFormStep(e) {
    e.preventDefault();
    setError("");

    const validationError = validateCurrentSection();
    if (validationError) {
      setError(validationError);
      requestAnimationFrame(() => {
        requestAnimationFrame(() => {
          stepErrorRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" });
        });
      });
      return;
    }

    const cacheKey = sectionCacheKey(currentSection.section_id);
    const mergedCache = {
      ...sectionCacheRef.current,
      [cacheKey]: snapshotCurrentSection()
    };
    setSectionCacheBoth(mergedCache);

    const isLastSection = sectionIndex >= orderedSections.length - 1;
    if (!isLastSection) {
      const nextIdx = sectionIndex + 1;
      const nextSection = orderedSections[nextIdx];
      setSectionIndex(nextIdx);
      applySectionSnapshot(
        mergedCache[sectionCacheKey(nextSection.section_id)],
        nextSection
      );
      window.scrollTo({ top: 0, behavior: "smooth" });
      return;
    }

    const pid = Number(permitId);
    const fid = Number(formId);
    const submitterId = Number(auth?.user?.user_id);

    const missingSections = findUncachedSections(orderedSections, mergedCache);
    if (missingSections.length) {
      setError(formatMissingSectionsError(missingSections, orderedSections));
      return;
    }

    setSubmitting(true);
    try {
      const permitVideoFiles = permitVideoCommitted ? [] : resolvePermitVideo();
      const permitVideoSectionId = permitVideoFiles.length
        ? findPermitVideoSectionId(orderedSections, mergedCache, sectionCacheKey)
        : null;

      if (needsPermitVideo && !permitVideoCommitted && !permitVideoFiles.length) {
        throw new Error("Upload a permit video before submitting.");
      }
      if (permitVideoFiles.length) {
        const videoErr = validateSectionVideoFiles(permitVideoFiles, "Permit video");
        if (videoErr) throw new Error(videoErr);
      }

      const { answers: allAnswers, mediaByQuestion: allMedia, sectionMedia } =
        buildFullSubmissionFromCache(
          orderedSections,
          mergedCache,
          questionTypeOptions,
          permitVideoFiles,
          permitVideoSectionId
        );

      if (workflowPhase === WORKFLOW.GENERAL) {
        const permitRow = await getPermit(pid);
        if (permitRow?.valid_from) {
          throw new Error(
            "This permit already has an opening submission. Use Start another PTW for a new permit, or continue with specialized permits if you already submitted."
          );
        }
      }

      if (!allAnswers.length) {
        throw new Error("No answers to submit.");
      }

      const payload = {
        permit_id: pid,
        form_id: fid,
        answers: allAnswers
      };
      if (workflowPhase === WORKFLOW.GENERAL) {
        payload.submission_role = "opening";
      }
      if (Number.isFinite(submitterId) && submitterId > 0) {
        payload.submitter_id = submitterId;
      }

      const result = await createSubmission(payload, allMedia, sectionMedia);
      setLastSectionResult(result);
      const newSubmissionId = result?.submission_id ?? null;
      setSubmissionId(newSubmissionId);

      if (workflowPhase === WORKFLOW.GENERAL && result?.valid_from && result?.valid_until) {
        setActivePermit({
          permitId: pid,
          permitNumber,
          validFrom: result.valid_from,
          validUntil: result.valid_until
        });
      }

      if (workflowPhase === WORKFLOW.GENERAL) {
        setExportSnapshot({
          permitNumber,
          orderedSections: [...orderedSections],
          sectionCache: mergedCache,
          questionTypeOptions,
          validFrom: result?.valid_from ?? null,
          validUntil: result?.valid_until ?? null
        });
        setGeneralSubmissionId(newSubmissionId);
        setFormDef(null);
        setSectionCacheBoth({});
        setShowSpecializedPicker(false);
        setWorkflowPhase(WORKFLOW.GENERAL_COMPLETE);
      } else {
        const completedJobType = specializedTypes.find(
          (t) => Number(t.job_type_id) === Number(selectedJobTypeId)
        );
        setSpecializedSubmissions((prev) => [
          ...prev,
          {
            submissionId: newSubmissionId,
            jobTypeName: completedJobType?.job_type_name || "Specialized permit"
          }
        ]);
        setFormDef(null);
        setFormComplete(false);
        setSectionCacheBoth({});
        setSelectedJobTypeId("");
        setShowSpecializedPicker(false);
        // Return to the permit hub so more specialized permits can be added.
        setWorkflowPhase(WORKFLOW.GENERAL_COMPLETE);
      }
    } catch (err) {
      setError(err?.response?.data?.message || err.message);
    } finally {
      setSubmitting(false);
    }
  }

  const isLastSection = sectionIndex >= orderedSections.length - 1;

  const progressPercent = orderedSections.length
    ? Math.round(((sectionIndex + 1) / orderedSections.length) * 100)
    : 0;

  const canAddSpecializedForm = specializedFormOptions.some((opt) => opt.form);
  const specializedFormReady =
    Boolean(selectedJobTypeId) && Boolean(selectedSpecializedForm);

  async function handleDownloadExcel() {
    if (!exportSnapshot) {
      setError("Excel export is unavailable for this session. Submit the general permit again to enable download.");
      return;
    }
    setExportingExcel(true);
    setError("");
    try {
      await downloadGeneralPtwExcel(exportSnapshot);
    } catch (err) {
      setError(err?.message || "Failed to generate Excel file.");
    } finally {
      setExportingExcel(false);
    }
  }

  function renderFormCompletionActions() {
    return (
      <footer className="ptw-form-fill-hub__actions">
        {exportSnapshot ? (
          <button
            type="button"
            className="swi-btn swi-btn--primary"
            onClick={handleDownloadExcel}
            disabled={exportingExcel}
          >
            {exportingExcel ? "Generating Excel…" : "Download Excel"}
          </button>
        ) : null}
        {canAddSpecializedForm ? (
          <button
            type="button"
            className="swi-btn swi-btn--primary"
            onClick={handleAddSpecializedForm}
            disabled={loadingForm || (showSpecializedPicker && !specializedFormReady)}
          >
            {loadingForm
              ? "Loading form…"
              : showSpecializedPicker
                ? specializedSubmissions.length
                  ? "Add another specialized form"
                  : "Continue with selected form"
                : specializedSubmissions.length
                  ? "Add another specialized form"
                  : "Add specialized form"}
          </button>
        ) : null}
        <button
          type="button"
          className={`swi-btn${canAddSpecializedForm ? " swi-btn--ghost" : " swi-btn--primary"}`}
          onClick={handleGoToPermitsList}
        >
          Permits &amp; Submissions
        </button>
      </footer>
    );
  }

  return (
    <div
      className={`portal-page ptw-form-fill-page${
        isDocumentFullLayout ? " portal-page--document-full" : ""
      }`}
    >
      <PageHeader
        title="Fill Permit Form"
        subtitle={
          workflowPhase === WORKFLOW.IDLE
            ? "Create and submit permits for safe work authorisation."
            : "Complete the general permit first, then optionally add specialized permits."
        }
        actions={(
          <button
            type="button"
            className="swi-btn swi-btn--ghost"
            onClick={loadMeta}
            disabled={loading}
          >
            {loading ? "Refreshing…" : "Refresh lists"}
          </button>
        )}
      />
      <ErrorBanner message={error || masterError} />

      {workflowPhase === WORKFLOW.ALL_COMPLETE ? (
        <section className="ptw-form-fill-landing">
          <div className="ptw-form-fill-hero ptw-form-fill-hub ptw-form-fill-hub--success">
            <div className="ptw-form-fill-hub__header">
              <div className="ptw-form-fill-result__icon" aria-hidden="true">✓</div>
              <div className="ptw-form-fill-hub__intro">
                <h2 className="ptw-form-fill-hub__title">PTW complete</h2>
                <p className="ptw-form-fill-hub__lead">
                  {permitNumber ? (
                    <>Permit <strong>{permitNumber}</strong> saved.</>
                  ) : (
                    <>Permit saved.</>
                  )}
                  {generalSubmissionId ? (
                    <> General submission #{generalSubmissionId}.</>
                  ) : null}
                  {specializedSubmissions.length ? (
                    <> {specializedSubmissions.length} specialized permit
                      {specializedSubmissions.length > 1 ? "s" : ""} added
                      ({specializedSubmissions.map((sp) => sp.jobTypeName).join(", ")}).</>
                  ) : null}
                </p>
              </div>
            </div>
            {renderFormCompletionActions()}
          </div>
        </section>
      ) : null}

      {workflowPhase === WORKFLOW.IDLE && loadingForm ? (
        <section className="ptw-form-fill-landing">
          <div className="ptw-form-fill-hero ptw-form-fill-hub">
            <p className="ptw-form-fill-hub__lead">Loading selected permit form…</p>
          </div>
        </section>
      ) : null}

      {workflowPhase === WORKFLOW.IDLE && !loadingForm ? (
        <section className="ptw-form-fill-landing">
          <div className="ptw-form-fill-hero">
            <header className="ptw-form-fill-hero__intro">
              <span className="ptw-form-fill-hero__badge">New permit workflow</span>
              <h2 className="ptw-form-fill-hero__title">Start a Permit to Work</h2>
              <p className="ptw-form-fill-hero__lead">
                Begin with a <strong>{generalJobType?.job_type_name || "GENERAL"}</strong> permit.
                Your progress is saved section by section and submitted together at the end.
              </p>
            </header>

            <ol className="ptw-form-fill-timeline" aria-label="Permit workflow steps">
              <li className="ptw-form-fill-timeline__step is-active">
                <span className="ptw-form-fill-timeline__marker" aria-hidden>1</span>
                <div className="ptw-form-fill-timeline__card">
                  <span className="ptw-form-fill-timeline__tag ptw-form-fill-timeline__tag--required">
                    Required
                  </span>
                  <strong>{generalJobType?.job_type_name || "GENERAL"} permit</strong>
                  <span>Complete all sections and submit to start the 8-hour validity window</span>
                </div>
              </li>
              <li className="ptw-form-fill-timeline__step">
                <span className="ptw-form-fill-timeline__marker" aria-hidden>2</span>
                <div className="ptw-form-fill-timeline__card">
                  <span className="ptw-form-fill-timeline__tag">Optional</span>
                  <strong>Specialized permit</strong>
                  <span>
                    {specializedTypes.length
                      ? specializedTypes.map((t) => t.job_type_name).join(", ")
                      : "No specialized types configured yet"}
                  </span>
                </div>
              </li>
              <li className="ptw-form-fill-timeline__step">
                <span className="ptw-form-fill-timeline__marker" aria-hidden>3</span>
                <div className="ptw-form-fill-timeline__card">
                  <span className="ptw-form-fill-timeline__tag">Complete</span>
                  <strong>Finish</strong>
                  <span>Permit saved — handover or handback before expiry if needed</span>
                </div>
              </li>
            </ol>

            <ul className="ptw-form-fill-features" aria-label="Key features">
              <li>
                <span className="ptw-form-fill-features__icon ptw-form-fill-features__icon--time" aria-hidden />
                <span><strong>8-hour validity</strong> from opening submission</span>
              </li>
              <li>
                <span className="ptw-form-fill-features__icon ptw-form-fill-features__icon--camera" aria-hidden />
                <span><strong>Video evidence</strong> for general, risk, and checklist sections</span>
              </li>
              <li>
                <span className="ptw-form-fill-features__icon ptw-form-fill-features__icon--save" aria-hidden />
                <span><strong>Section caching</strong> while you work through the form</span>
              </li>
            </ul>

            <div className="ptw-form-fill-types">
              <span className="ptw-form-fill-types__label">Available permit types</span>
              <div className="ptw-form-fill-types__chips">
                <span className="ptw-form-fill-type-chip ptw-form-fill-type-chip--primary">
                  {generalJobType?.job_type_name || "GENERAL"}
                  <em>Required</em>
                </span>
                {specializedTypes.map((jt) => (
                  <span key={jt.job_type_id} className="ptw-form-fill-type-chip">
                    {jt.job_type_name}
                    <em>Optional</em>
                  </span>
                ))}
              </div>
            </div>

            <footer className="ptw-form-fill-hero__footer">
              <button
                type="button"
                className="swi-btn swi-btn--primary ptw-form-fill-hero__cta"
                onClick={handleRequestStartPtw}
                disabled={loadingForm || loading || masterLoading || !generalJobType}
              >
                {loadingForm
                  ? "Starting…"
                  : `Start ${generalJobType?.job_type_name || "GENERAL"} permit`}
              </button>
              <p className="ptw-form-fill-hero__footnote">
                {masterLoading
                  ? "Loading permit types…"
                  : !generalJobType
                    ? "GENERAL job type (job_type_id 1) is missing from ptw_job_type. Seed it in the database before starting."
                    : "You can add specialized permits after the general permit is submitted."}
              </p>
            </footer>
          </div>
        </section>
      ) : null}

      {workflowPhase === WORKFLOW.GENERAL_COMPLETE ? (
        <section className="ptw-form-fill-landing">
          <div className="ptw-form-fill-hero ptw-form-fill-hub">
            <div className="ptw-form-fill-hub__header">
              <div className="ptw-form-fill-result__icon ptw-form-fill-result__icon--done" aria-hidden="true">✓</div>
              <div className="ptw-form-fill-hub__intro">
                <span className="ptw-form-fill-hero__badge">General permit saved</span>
                <h2 className="ptw-form-fill-hub__title">
                  {specializedSubmissions.length ? "Specialized permit added" : "General permit complete"}
                </h2>
                <p className="ptw-form-fill-hub__lead">
                  {permitNumber ? (
                    <>Permit <strong>{permitNumber}</strong> — general submission #{generalSubmissionId ?? "—"} saved.</>
                  ) : (
                    <>General submission #{generalSubmissionId ?? "—"} saved.</>
                  )}{" "}
                  {specializedSubmissions.length
                    ? "Choose another specialized permit form, or open the permits list."
                    : "Add a specialized permit form now, or open the permits list."}{" "}
                  You can return later from <strong>Permits &amp; Submissions</strong> to add more forms.
                </p>
                {lastSectionResult?.valid_from && lastSectionResult?.valid_until ? (
                  <p className="ptw-form-fill-hub__validity">
                    Permit valid from <strong>{formatPermitValidity(lastSectionResult.valid_from)}</strong> until{" "}
                    <strong>{formatPermitValidity(lastSectionResult.valid_until)}</strong> (8 hours).
                  </p>
                ) : null}
              </div>
            </div>

            {specializedSubmissions.length ? (
              <ul className="ptw-form-fill-hub__completed">
                {specializedSubmissions.map((sp) => (
                  <li key={sp.submissionId ?? sp.jobTypeName}>
                    <strong>{sp.jobTypeName}</strong> added
                    {sp.submissionId ? <> — submission #{sp.submissionId}</> : null}
                  </li>
                ))}
              </ul>
            ) : null}

            {showSpecializedPicker && specializedFormOptions.length ? (
              <div className="ptw-form-fill-hub__picker">
                <label className="ptw-form-fill-hub__field" htmlFor="ptw-specialized-form-select">
                  <span className="ptw-form-fill-hub__label">Specialized permit form</span>
                  <select
                    id="ptw-specialized-form-select"
                    className="swi-input ptw-form-fill-hub__select"
                    value={selectedJobTypeId}
                    onChange={(e) => setSelectedJobTypeId(e.target.value)}
                  >
                    <option value="">Select a specialized permit…</option>
                    {specializedFormOptions.map((opt) => (
                      <option key={opt.jobTypeId} value={opt.jobTypeId} disabled={!opt.form}>
                        {opt.label}
                      </option>
                    ))}
                  </select>
                </label>
                {selectedJobTypeId && !selectedSpecializedForm ? (
                  <p className="ptw-form-fill-hub__hint ptw-form-fill-hub__hint--warn">
                    No form is linked to this job type. Configure one in Form Management.
                  </p>
                ) : selectedSpecializedForm ? (
                  <p className="ptw-form-fill-hub__hint">
                    Form #{selectedSpecializedForm.form_id} will open for{" "}
                    <strong>
                      {specializedFormOptions.find((o) => o.jobTypeId === String(selectedJobTypeId))?.jobTypeName}
                    </strong>
                    .
                  </p>
                ) : null}
              </div>
            ) : showSpecializedPicker && !specializedFormOptions.length ? (
              <p className="ptw-form-fill-hub__empty">No specialized job types configured.</p>
            ) : null}

            {renderFormCompletionActions()}
          </div>
        </section>
      ) : null}

      {formDef &&
      (workflowPhase === WORKFLOW.GENERAL || workflowPhase === WORKFLOW.SPECIALIZED) &&
      !formComplete &&
      !orderedSections.length ? (
        <section className="ptw-form-fill-shell ptw-form-fill-result">
          <h2 className="ptw-form-fill-result__title">No fillable sections</h2>
          <p className="ptw-form-fill-result__text">
            This form has no sections mapped. Add sections in Form Management and link them to
            this form.
          </p>
          <button type="button" className="swi-btn swi-btn--ghost" onClick={handleStartAnother}>
            Back
          </button>
        </section>
      ) : null}

      {formDef && (workflowPhase === WORKFLOW.GENERAL || workflowPhase === WORKFLOW.SPECIALIZED) && !formComplete && currentSection ? (
        <>
          <PtwSectionProgress
            sections={orderedSections.map((section) => ({
              id: section.section_id,
              title: section.title,
            }))}
            activeIndex={sectionIndex}
            cachedSectionIds={Object.keys(sectionCache)}
            percent={progressPercent}
            jobTypeName={
              workflowPhase === WORKFLOW.GENERAL
                ? generalJobType?.job_type_name || "GENERAL"
                : specializedTypes.find(
                    (t) => Number(t.job_type_id) === Number(selectedJobTypeId)
                  )?.job_type_name || "SPECIALIZED"
            }
            permitNumber={permitNumber}
          />
          <form className="ptw-form-fill ptw-form-fill--document" onSubmit={handleFormStep}>
            <PtwFormDocument
              jobTypeName={
                workflowPhase === WORKFLOW.GENERAL
                  ? generalJobType?.job_type_name || "GENERAL"
                  : specializedTypes.find(
                      (t) => Number(t.job_type_id) === Number(selectedJobTypeId)
                    )?.job_type_name || "SPECIALIZED"
              }
              permitNumber={permitNumber}
              jobColor={jobColor}
            >
            <PtwDocumentSection
              section={currentSection}
              sectionKind={sectionKind}
              sectionSkipable={sectionSkipable}
              questions={currentSection.questions || []}
              questionTypeOptions={questionTypeOptions}
              answers={answers}
              setAnswer={setAnswer}
              mediaByQuestion={mediaByQuestion}
              setMedia={setMedia}
              showPermitVideoUpload={showPermitVideoUpload}
              permitVideoUploaded={hasPersistedPermitVideo}
              onPermitVideoUpload={handlePermitVideoUpload}
              permitVideoInputRef={permitVideoInputRef}
              skipChoice={skipChoice}
              setSkipChoice={handleSkipChoice}
              skipReference={skipReference}
              setSkipReference={setSkipReference}
              skipNotes={skipNotes}
              setSkipNotes={setSkipNotes}
              riskVisibleRowCount={riskVisibleRowCount}
              onRiskVisibleRowCountChange={setRiskVisibleRowCount}
              formMeta={formDef}
              formTypes={data.ptw_form_type || []}
            />
          </PtwFormDocument>

          <div className="ptw-doc-footer" ref={stepErrorRef}>
            {error ? (
              <p className="ptw-doc-footer__error swi-error" role="alert">
                {error}
              </p>
            ) : null}
            <p className="ptw-doc-footer__hint">
              {isLastSection
                ? "Submit sends all cached sections to the server in one submission."
                : "Your answers for this section will be cached locally when you continue."}
            </p>
            <button type="submit" className="swi-btn swi-btn--primary" disabled={submitting}>
              {submitting
                ? "Submitting form…"
                : isLastSection
                  ? "Submit form"
                  : "Next section"}
            </button>
          </div>
          </form>
        </>
      ) : null}

      <PermitEntryWarningModal
        open={entryWarningOpen}
        confirming={loadingForm}
        onCancel={() => {
          if (!loadingForm) setEntryWarningOpen(false);
        }}
        onConfirm={handleConfirmStartPtw}
      />
    </div>
  );
}
