import {
  useEffect,
  useState
} from "react";

import {
  useNavigate,
  useOutletContext
} from "react-router-dom";

import ConfirmationModal from "../../../components/modals/ConfirmationModal";

import {
  getCorrectionStatus,
  getDeclaration,
  resubmitCorrection,
  saveDeclarationDraft,
  submitFinalDeclaration
} from "../../../services/publicPortalService";

const Declaration = () => {
  const navigate =
    useNavigate();

  const outletContext =
    useOutletContext() || {};

  const {
    refreshProgress
  } = outletContext;

  const [
    declarationAccepted,
    setDeclarationAccepted
  ] = useState(false);

  const [
    declaredFullName,
    setDeclaredFullName
  ] = useState("");

  const [
    expectedFullName,
    setExpectedFullName
  ] = useState("");

  const [
    submissionReference,
    setSubmissionReference
  ] = useState("");

  const [
    correctionData,
    setCorrectionData
  ] = useState(null);

  const [
    staffResponseNote,
    setStaffResponseNote
  ] = useState("");

  const [
    showSubmitConfirmation,
    setShowSubmitConfirmation
  ] = useState(false);

  const [
    loading,
    setLoading
  ] = useState(true);

  const [
    saving,
    setSaving
  ] = useState(false);

  const [
    submitting,
    setSubmitting
  ] = useState(false);

  const [
    editable,
    setEditable
  ] = useState(true);

  const [
    error,
    setError
  ] = useState("");

  const [
    successMessage,
    setSuccessMessage
  ] = useState("");

  const [
    fieldErrors,
    setFieldErrors
  ] = useState({});

  const isCorrectionMode =
    correctionData
      ?.requires_correction ===
    true;

  useEffect(() => {
    let componentMounted = true;

    const loadDeclaration =
      async () => {
        try {
          setLoading(true);
          setError("");

          const [
            declarationResult,
            correctionResult
          ] = await Promise.all([
            getDeclaration(),
            getCorrectionStatus()
          ]);

          if (!componentMounted) {
            return;
          }

          const responseData =
            declarationResult?.data ||
            {};

          const declaration =
            responseData.declaration ||
            {};

          const correctionResponse =
            correctionResult?.data ||
            null;

          setCorrectionData(
            correctionResponse
          );

          setStaffResponseNote(
            correctionResponse
              ?.correction
              ?.staff_response_note ||
              ""
          );

          setEditable(
            responseData.editable !==
              false
          );

          setExpectedFullName(
            responseData.staff
              ?.full_name ||
              ""
          );

          setSubmissionReference(
            responseData.submission
              ?.submission_reference ||
              correctionResponse
                ?.submission
                ?.submission_reference ||
              ""
          );

          setDeclarationAccepted(
            declaration
              .declaration_accepted ===
              true ||
              Number(
                declaration
                  .declaration_accepted
              ) === 1
          );

          setDeclaredFullName(
            declaration
              .declared_full_name ||
              ""
          );
        } catch (requestError) {
          console.error(
            "Load declaration error:",
            requestError
          );

          if (!componentMounted) {
            return;
          }

          setError(
            requestError.response?.data
              ?.message ||
              requestError.message ||
              "Unable to load the declaration."
          );
        } finally {
          if (componentMounted) {
            setLoading(false);
          }
        }
      };

    loadDeclaration();

    return () => {
      componentMounted = false;
    };
  }, []);

  const clearMessages = () => {
    setError("");
    setSuccessMessage("");
  };

  const clearFieldError = (
    fieldName
  ) => {
    setFieldErrors(
      (currentErrors) => {
        const nextErrors = {
          ...currentErrors
        };

        delete nextErrors[
          fieldName
        ];

        return nextErrors;
      }
    );
  };

  const handleAcceptanceChange = (
    event
  ) => {
    setDeclarationAccepted(
      event.target.checked
    );

    clearFieldError(
      "declaration_accepted"
    );

    clearFieldError(
      "declaration"
    );

    clearMessages();
  };

  const handleNameChange = (
    event
  ) => {
    setDeclaredFullName(
      event.target.value
    );

    clearFieldError(
      "declared_full_name"
    );

    clearFieldError(
      "declaration"
    );

    clearMessages();
  };

  const handleResponseNoteChange = (
    event
  ) => {
    setStaffResponseNote(
      event.target.value
    );

    clearFieldError(
      "staff_response_note"
    );

    clearMessages();
  };

  const refreshFormProgress =
    async () => {
      if (
        typeof refreshProgress !==
        "function"
      ) {
        return;
      }

      try {
        await refreshProgress();
      } catch (progressError) {
        /*
         * Do not make an otherwise successful
         * save or submission appear to have
         * failed only because progress refresh
         * did not complete.
         */
        console.error(
          "Refresh progress error:",
          progressError
        );
      }
    };

  const handleSaveDraft =
    async () => {
      try {
        setSaving(true);
        setError("");
        setSuccessMessage("");
        setFieldErrors({});

        const result =
          await saveDeclarationDraft({
            declaration_accepted:
              declarationAccepted,

            declared_full_name:
              declaredFullName.trim()
          });

        setSuccessMessage(
          result?.message ||
            (
              isCorrectionMode
                ? "Correction declaration saved successfully."
                : "Declaration saved as a draft."
            )
        );

        await refreshFormProgress();
      } catch (requestError) {
        console.error(
          "Save declaration draft error:",
          requestError
        );

        const responseData =
          requestError.response?.data;

        setError(
          responseData?.message ||
            requestError.message ||
            "Unable to save the declaration draft."
        );

        setFieldErrors(
          responseData?.errors ||
            {}
        );
      } finally {
        setSaving(false);
      }
    };

  const openSubmitConfirmation =
    () => {
      const validationErrors = {};

      if (!declarationAccepted) {
        validationErrors
          .declaration_accepted =
          "You must accept the declaration before submitting.";
      }

      if (
        !declaredFullName.trim()
      ) {
        validationErrors
          .declared_full_name =
          "Enter your full name before submitting.";
      }

      if (
        isCorrectionMode &&
        staffResponseNote
          .trim()
          .length < 10
      ) {
        validationErrors
          .staff_response_note =
          "Briefly describe the corrections you made using at least 10 characters.";
      }

      if (
        Object.keys(
          validationErrors
        ).length > 0
      ) {
        setFieldErrors(
          validationErrors
        );

        setError(
          isCorrectionMode
            ? "Complete the correction resubmission requirements."
            : "Complete the declaration requirements before submitting."
        );

        setSuccessMessage("");

        return;
      }

      setError("");
      setSuccessMessage("");
      setFieldErrors({});

      setShowSubmitConfirmation(
        true
      );
    };

  const closeSubmitConfirmation =
    () => {
      if (submitting) {
        return;
      }

      setShowSubmitConfirmation(
        false
      );
    };

  const handleFinalSubmission =
    async () => {
      try {
        setSubmitting(true);
        setError("");
        setSuccessMessage("");
        setFieldErrors({});

        let result;

        if (isCorrectionMode) {
          /*
           * Save the latest declaration values
           * before changing the returned record
           * back to submitted status.
           */
          await saveDeclarationDraft({
            declaration_accepted:
              declarationAccepted,

            declared_full_name:
              declaredFullName.trim()
          });

          result =
            await resubmitCorrection({
              staff_response_note:
                staffResponseNote.trim()
            });
        } else {
          result =
            await submitFinalDeclaration({
              declaration_accepted:
                declarationAccepted,

              declared_full_name:
                declaredFullName.trim()
            });
        }

        const submissionResult = {
          ...(result?.data || {}),

          is_resubmission:
            isCorrectionMode ||
            result?.data
              ?.is_resubmission ===
              true,

          message:
            result?.message ||
            (
              isCorrectionMode
                ? "Your corrected staff records have been resubmitted to HR successfully."
                : "Your staff records have been submitted successfully."
            )
        };

        sessionStorage.setItem(
          "finalSubmissionResult",
          JSON.stringify(
            submissionResult
          )
        );

        setShowSubmitConfirmation(
          false
        );

        await refreshFormProgress();

        navigate(
          "/staff/submission-success",
          {
            replace: true
          }
        );
      } catch (requestError) {
        console.error(
          isCorrectionMode
            ? "Correction resubmission error:"
            : "Final declaration submission error:",
          requestError
        );

        const responseData =
          requestError.response?.data;

        setShowSubmitConfirmation(
          false
        );

        setError(
          responseData?.message ||
            requestError.message ||
            (
              isCorrectionMode
                ? "Unable to resubmit the corrected staff record."
                : "Unable to submit the staff records update."
            )
        );

        setFieldErrors(
          responseData?.errors ||
            {}
        );
      } finally {
        setSubmitting(false);
      }
    };

  if (loading) {
    return (
      <div className="form-page-card">
        <div className="information-banner">
          Loading declaration...
        </div>
      </div>
    );
  }

  const isBusy =
    saving ||
    submitting;

  return (
    <div className="form-page-card">
      <div className="form-page-heading">
        <div>
          <span>
            {isCorrectionMode
              ? "Correction Resubmission"
              : "Declaration"}
          </span>

          <h2>
            {isCorrectionMode
              ? "Declaration and Correction Resubmission"
              : "Declaration and Final Submission"}
          </h2>

          <p>
            {isCorrectionMode
              ? "Confirm that the requested corrections have been completed before resubmitting your staff record to HR."
              : "Review the declaration carefully before submitting your staff records update."}
          </p>
        </div>

        <span className="form-step-badge">
          Step 8 of 8
        </span>
      </div>

      {submissionReference && (
        <div className="declaration-reference">
          <span>
            Submission Reference
          </span>

          <strong>
            {submissionReference}
          </strong>
        </div>
      )}

      {isCorrectionMode && (
        <div className="final-submission-warning">
          <strong>
            Correction Resubmission
          </strong>

          <p>
            Your record was returned by HR.
            Review all requested corrections,
            save the affected sections and
            provide a summary of the changes
            before resubmitting.
          </p>

          {correctionData
            ?.correction
            ?.return_reason && (
            <div className="staff-correction-reason">
              <strong>
                Reason from HR
              </strong>

              <p>
                {
                  correctionData
                    .correction
                    .return_reason
                }
              </p>
            </div>
          )}
        </div>
      )}

      {!editable && (
        <div className="form-alert form-alert--error">
          This submission is no longer
          editable.
        </div>
      )}

      {error && (
        <div
          className="form-alert form-alert--error"
          role="alert"
        >
          {error}
        </div>
      )}

      {successMessage && (
        <div
          className="form-alert form-alert--success"
          role="status"
        >
          {successMessage}
        </div>
      )}

      {Array.isArray(
        fieldErrors.sections
      ) &&
        fieldErrors.sections.length >
          0 && (
          <div className="incomplete-sections-alert">
            <strong>
              Complete these sections before
              submitting:
            </strong>

            <ul>
              {fieldErrors.sections.map(
                (section) => (
                  <li key={section}>
                    {section}
                  </li>
                )
              )}
            </ul>
          </div>
        )}

      {fieldErrors.declaration && (
        <div className="form-alert form-alert--error">
          {fieldErrors.declaration}
        </div>
      )}

      <section className="declaration-statement">
        <h3>
          Staff Declaration
        </h3>

        <p>
          I declare that the information
          provided in this staff records
          update is complete and accurate to
          the best of my knowledge.
        </p>

        <p>
          I understand that the Controller and
          Accountant-General&apos;s Department
          may verify the information and
          supporting documents provided.
        </p>

        <p>
          I understand that submitting false,
          misleading or incomplete information
          may result in administrative action.
        </p>
      </section>

      <label className="declaration-checkbox">
        <input
          type="checkbox"
          checked={
            declarationAccepted
          }
          onChange={
            handleAcceptanceChange
          }
          disabled={
            isBusy ||
            !editable
          }
        />

        <span>
          I have read and accept the
          declaration above.
        </span>
      </label>

      {fieldErrors
        .declaration_accepted && (
        <small className="field-error">
          {
            fieldErrors
              .declaration_accepted
          }
        </small>
      )}

      <div className="form-group declaration-name-field">
        <label htmlFor="declared_full_name">
          Type Your Full Name

          <span className="required-mark">
            *
          </span>
        </label>

        <input
          id="declared_full_name"
          name="declared_full_name"
          type="text"
          value={
            declaredFullName
          }
          onChange={
            handleNameChange
          }
          maxLength={150}
          disabled={
            isBusy ||
            !editable
          }
          placeholder={
            expectedFullName
          }
          autoComplete="name"
        />

        <small className="field-help">
          Enter your name exactly as shown:

          <strong>
            {" "}
            {expectedFullName}
          </strong>
        </small>

        {fieldErrors
          .declared_full_name && (
          <small className="field-error">
            {
              fieldErrors
                .declared_full_name
            }
          </small>
        )}
      </div>

      {isCorrectionMode && (
        <div className="form-group correction-response-field">
          <label htmlFor="staff_response_note">
            Summary of Corrections Made

            <span className="required-mark">
              *
            </span>
          </label>

          <textarea
            id="staff_response_note"
            name="staff_response_note"
            value={
              staffResponseNote
            }
            onChange={
              handleResponseNoteChange
            }
            rows={5}
            maxLength={2000}
            disabled={
              isBusy ||
              !editable
            }
            placeholder="Briefly explain what you corrected before resubmitting to HR"
          />

          <small className="field-help">
            Example: Corrected my residential
            address and uploaded the requested
            professional certificate.
          </small>

          {fieldErrors
            .staff_response_note && (
            <small className="field-error">
              {
                fieldErrors
                  .staff_response_note
              }
            </small>
          )}
        </div>
      )}

      <div className="final-submission-warning">
        <strong>
          Important
        </strong>

        <p>
          {isCorrectionMode
            ? "After resubmission, the form will be locked while HR reviews the corrected record."
            : "After final submission, the form will be locked and cannot be edited unless it is returned by HR for correction."}
        </p>
      </div>

      <div className="form-action-bar">
        <button
          type="button"
          className="secondary-button"
          onClick={() =>
            navigate(
              "/staff/form/documents"
            )
          }
          disabled={isBusy}
        >
          Previous
        </button>

        <button
          type="button"
          className="secondary-button"
          onClick={
            handleSaveDraft
          }
          disabled={
            isBusy ||
            !editable
          }
        >
          {saving
            ? "Saving..."
            : "Save draft"}
        </button>

        <button
          type="button"
          className="primary-button final-submit-button"
          onClick={
            openSubmitConfirmation
          }
          disabled={
            isBusy ||
            !editable
          }
        >
          {submitting
            ? (
                isCorrectionMode
                  ? "Resubmitting..."
                  : "Submitting..."
              )
            : (
                isCorrectionMode
                  ? "Resubmit corrected records"
                  : "Submit staff records update"
              )}
        </button>
      </div>

      <ConfirmationModal
        open={
          showSubmitConfirmation
        }
        title={
          isCorrectionMode
            ? "Confirm Correction Resubmission"
            : "Confirm Final Submission"
        }
        message={
          isCorrectionMode
            ? "Are you sure you have completed the requested corrections? The updated record will be sent back to HR for another review."
            : "Are you sure you want to submit your staff records update? After submission, the form will be locked and you will not be able to make further changes."
        }
        confirmText={
          isCorrectionMode
            ? "Yes, resubmit to HR"
            : "Yes, submit record"
        }
        cancelText="Continue editing"
        loading={submitting}
        onCancel={
          closeSubmitConfirmation
        }
        onConfirm={
          handleFinalSubmission
        }
      />
    </div>
  );
};

export default Declaration;