import {
  useCallback,
  useEffect,
  useRef,
  useState
} from "react";

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

import {
  deleteDocument,
  downloadDocument,
  getDocuments,
  saveDocumentsSection,
  uploadDocument
} from "../../../services/publicPortalService";

const MAX_FILE_SIZE_BYTES =
  10 * 1024 * 1024;

const allowedMimeTypes = [
  "application/pdf",
  "image/jpeg",
  "image/png"
];

const allowedExtensions = [
  "pdf",
  "jpg",
  "jpeg",
  "png"
];

const documentTypeOptions = [
  {
    value: "academic_certificate",
    label: "Academic Certificate"
  },
  {
    value: "professional_certificate",
    label: "Professional Certificate"
  },
  {
    value: "appointment_letter",
    label: "Appointment Letter"
  },
  {
    value: "promotion_letter",
    label: "Promotion Letter"
  },
  {
    value: "other",
    label: "Other Supporting Document"
  }
];

const initialUploadForm = {
  document_type: "",
  document_title: "",
  document: null
};

const formatFileSize = (fileSize) => {
  const bytes = Number(fileSize) || 0;

  if (bytes < 1024) {
    return `${bytes} bytes`;
  }

  if (bytes < 1024 * 1024) {
    return `${(bytes / 1024).toFixed(1)} KB`;
  }

  return `${(
    bytes /
    (1024 * 1024)
  ).toFixed(2)} MB`;
};

const getDocumentTypeLabel = (
  documentType
) => {
  return (
    documentTypeOptions.find(
      (option) =>
        option.value === documentType
    )?.label ||
    "Supporting Document"
  );
};

const getFileExtension = (fileName) => {
  const parts =
    String(fileName || "")
      .toLowerCase()
      .split(".");

  return parts.length > 1
    ? parts.pop()
    : "";
};

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

  const outletContext =
    useOutletContext();

  const refreshProgress =
    outletContext?.refreshProgress;

  const fileInputRef =
    useRef(null);

  const [
    hasNewDocuments,
    setHasNewDocuments
  ] = useState("");

  const [
    documents,
    setDocuments
  ] = useState([]);

  const [
    uploadForm,
    setUploadForm
  ] = useState(
    initialUploadForm
  );

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

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

  const [uploading, setUploading] =
    useState(false);

  const [
    processingDocumentId,
    setProcessingDocumentId
  ] = useState(null);

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

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

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

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

  const refreshSectionProgress =
    async () => {
      if (
        typeof refreshProgress ===
        "function"
      ) {
        await refreshProgress();
      }
    };

  const loadDocuments = useCallback(
    async ({
      showLoader = true
    } = {}) => {
      try {
        if (showLoader) {
          setLoading(true);
        }

        setError("");

        const result =
          await getDocuments();

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

        const summary =
          responseData.summary || {};

        const savedValue =
          summary.has_new_documents;

        let statusValue = "";

        if (
          savedValue === true ||
          savedValue === 1 ||
          savedValue === "1"
        ) {
          statusValue = "yes";
        } else if (
          savedValue === false ||
          savedValue === 0 ||
          savedValue === "0"
        ) {
          statusValue = "no";
        }

        setEditable(
          responseData.editable !==
            false
        );

        setHasNewDocuments(
          statusValue
        );

        setDocuments(
          Array.isArray(
            responseData.documents
          )
            ? responseData.documents
            : []
        );
      } catch (requestError) {
        console.error(
          "Load documents error:",
          requestError
        );

        setError(
          requestError.response?.data
            ?.message ||
            requestError.message ||
            "Unable to load supporting documents."
        );
      } finally {
        if (showLoader) {
          setLoading(false);
        }
      }
    },
    []
  );

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

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

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

        delete nextErrors[
          fieldName
        ];

        return nextErrors;
      }
    );
  };

  const handleDocumentStatusChange = (
    event
  ) => {
    const nextValue =
      event.target.value;

    setHasNewDocuments(
      nextValue
    );

    setFieldErrors({});
    clearMessages();
  };

  const handleUploadFieldChange = (
    event
  ) => {
    const {
      name,
      value
    } = event.target;

    setUploadForm(
      (currentForm) => {
        const nextForm = {
          ...currentForm,
          [name]: value
        };

        if (
          name ===
            "document_type" &&
          value !== "other"
        ) {
          /*
           * Keep an optional title for the
           * standard document categories.
           */
          nextForm.document_title =
            currentForm.document_title;
        }

        return nextForm;
      }
    );

    clearFieldError(name);
    clearMessages();
  };

  const handleFileChange = (
    event
  ) => {
    const selectedFile =
      event.target.files?.[0] ||
      null;

    setUploadForm(
      (currentForm) => ({
        ...currentForm,
        document: selectedFile
      })
    );

    clearFieldError(
      "document"
    );

    clearMessages();
  };

  const resetUploadForm = () => {
    setUploadForm({
      ...initialUploadForm
    });

    if (fileInputRef.current) {
      fileInputRef.current.value =
        "";
    }
  };

  const validateSelectedFile = (
    selectedFile
  ) => {
    if (!selectedFile) {
      return "Select a file to upload.";
    }

    const fileExtension =
      getFileExtension(
        selectedFile.name
      );

    const validMimeType =
      allowedMimeTypes.includes(
        selectedFile.type
      );

    const validExtension =
      allowedExtensions.includes(
        fileExtension
      );

    if (
      !validMimeType ||
      !validExtension
    ) {
      return (
        "Only PDF, JPG, JPEG and PNG " +
        "files are permitted."
      );
    }

    if (
      selectedFile.size >
      MAX_FILE_SIZE_BYTES
    ) {
      return (
        "The selected file exceeds " +
        "the 10 MB limit."
      );
    }

    if (selectedFile.size < 1) {
      return (
        "The selected file is empty."
      );
    }

    return "";
  };

  const handleUpload = async () => {
    /*
     * Use both React state and the actual
     * browser input as a fallback.
     */
    const selectedFile =
      uploadForm.document ||
      fileInputRef.current
        ?.files?.[0] ||
      null;

    const localErrors = {};

    if (
      !uploadForm.document_type
    ) {
      localErrors.document_type =
        "Select a document type.";
    }

    if (
      uploadForm.document_type ===
        "other" &&
      !uploadForm.document_title.trim()
    ) {
      localErrors.document_title =
        "Enter a title for the document.";
    }

    const fileError =
      validateSelectedFile(
        selectedFile
      );

    if (fileError) {
      localErrors.document =
        fileError;
    }

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

      setError(
        "Complete the document information before uploading."
      );

      return;
    }

    try {
      setUploading(true);
      setError("");
      setSuccessMessage("");
      setFieldErrors({});

      const result =
        await uploadDocument({
          document_type:
            uploadForm.document_type,

          document_title:
            uploadForm.document_title
              .trim(),

          document:
            selectedFile
        });

      resetUploadForm();

      /*
       * Reload from the backend so that
       * the interface reflects what was
       * actually saved in the database.
       */
      await loadDocuments({
        showLoader: false
      });

      setHasNewDocuments(
        "yes"
      );

      setSuccessMessage(
        result?.message ||
          "Document uploaded successfully."
      );

      await refreshSectionProgress();
    } catch (requestError) {
      console.error(
        "Upload document error:",
        requestError
      );

      const responseData =
        requestError.response?.data;

      setError(
        responseData?.message ||
          requestError.message ||
          "Unable to upload the document."
      );

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

  const handleDelete = async (
    document
  ) => {
    const confirmed =
      window.confirm(
        `Remove "${document.original_file_name}"?`
      );

    if (!confirmed) {
      return;
    }

    try {
      setProcessingDocumentId(
        document.id
      );

      setError("");
      setSuccessMessage("");

      const result =
        await deleteDocument(
          document.id
        );

      await loadDocuments({
        showLoader: false
      });

      setSuccessMessage(
        result?.message ||
          "Document removed successfully."
      );

      await refreshSectionProgress();
    } catch (requestError) {
      console.error(
        "Delete document error:",
        requestError
      );

      setError(
        requestError.response?.data
          ?.message ||
          requestError.message ||
          "Unable to remove the document."
      );
    } finally {
      setProcessingDocumentId(
        null
      );
    }
  };

  const handleDownload = async (
    document
  ) => {
    try {
      setProcessingDocumentId(
        document.id
      );

      setError("");

      const documentBlob =
        await downloadDocument(
          document.id
        );

      const downloadUrl =
        URL.createObjectURL(
          documentBlob
        );

      const temporaryLink =
        window.document.createElement(
          "a"
        );

      temporaryLink.href =
        downloadUrl;

      temporaryLink.download =
        document.original_file_name;

      window.document.body.appendChild(
        temporaryLink
      );

      temporaryLink.click();
      temporaryLink.remove();

      URL.revokeObjectURL(
        downloadUrl
      );
    } catch (requestError) {
      console.error(
        "Download document error:",
        requestError
      );

      setError(
        requestError.response?.data
          ?.message ||
          requestError.message ||
          "Unable to download the document."
      );
    } finally {
      setProcessingDocumentId(
        null
      );
    }
  };

  const submitDocumentsSection =
    async ({
      markCompleted
    }) => {
      if (
        markCompleted &&
        hasNewDocuments === "yes" &&
        documents.length === 0
      ) {
        setError(
          "Upload the selected document before continuing."
        );

        setFieldErrors({
          documents:
            "Click Upload document and wait until the file appears under Uploaded Documents."
        });

        return;
      }

      if (
        hasNewDocuments === "no" &&
        documents.length > 0
      ) {
        setError(
          "You already have uploaded documents."
        );

        setFieldErrors({
          documents:
            "Remove the uploaded documents or select Yes."
        });

        return;
      }

      try {
        setSaving(true);
        setError("");
        setSuccessMessage("");
        setFieldErrors({});

        const normalizedStatus =
          hasNewDocuments === ""
            ? null
            : hasNewDocuments ===
              "yes";

        const result =
          await saveDocumentsSection({
            has_new_documents:
              normalizedStatus,

            mark_completed:
              markCompleted
          });

        setSuccessMessage(
          result?.message ||
            "Supporting documents saved successfully."
        );

        await refreshSectionProgress();

        if (markCompleted) {
          navigate(
            "/staff/form/declaration"
          );
        }
      } catch (requestError) {
        console.error(
          "Save document section error:",
          requestError
        );

        const responseData =
          requestError.response?.data;

        setError(
          responseData?.message ||
            requestError.message ||
            "Unable to save the supporting-documents section."
        );

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

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

  const isBusy =
    saving ||
    uploading ||
    processingDocumentId !== null;

  const requiresDocumentUpload =
    hasNewDocuments === "yes" &&
    documents.length === 0;

  return (
    <div className="form-page-card">
      <div className="form-page-heading">
        <div>
          <span>
            Supporting Documents
          </span>

          <h2>
            Supporting Documents
          </h2>

          <p>
            Upload copies of new academic,
            professional, appointment or
            promotion documents.
          </p>
        </div>

        <span className="form-step-badge">
          Step 7 of 8
        </span>
      </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">
          {successMessage}
        </div>
      )}

      <div className="form-group">
        <label htmlFor="has_new_documents">
          Do you have new supporting
          documents to upload?
          <span className="required-mark">
            *
          </span>
        </label>

        <select
          id="has_new_documents"
          value={hasNewDocuments}
          onChange={
            handleDocumentStatusChange
          }
          disabled={
            isBusy ||
            !editable
          }
        >
          <option value="">
            Select an option
          </option>

          <option value="yes">
            Yes
          </option>

          <option value="no">
            No
          </option>
        </select>

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

      {hasNewDocuments === "yes" && (
        <section className="document-upload-panel">
          <div className="document-upload-panel__heading">
            <h3>
              Upload a document
            </h3>

            <p>
              Accepted formats: PDF, JPG,
              JPEG and PNG. Maximum file
              size: 10 MB.
            </p>
          </div>

          <div className="form-grid form-grid--two">
            <div className="form-group">
              <label htmlFor="document_type">
                Document Type
                <span className="required-mark">
                  *
                </span>
              </label>

              <select
                id="document_type"
                name="document_type"
                value={
                  uploadForm.document_type
                }
                onChange={
                  handleUploadFieldChange
                }
                disabled={
                  isBusy ||
                  !editable
                }
              >
                <option value="">
                  Select document type
                </option>

                {documentTypeOptions.map(
                  (option) => (
                    <option
                      key={option.value}
                      value={option.value}
                    >
                      {option.label}
                    </option>
                  )
                )}
              </select>

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

            <div className="form-group">
              <label htmlFor="document_title">
                Document Title

                {uploadForm
                  .document_type ===
                  "other" && (
                  <span className="required-mark">
                    *
                  </span>
                )}
              </label>

              <input
                id="document_title"
                name="document_title"
                type="text"
                value={
                  uploadForm.document_title
                }
                onChange={
                  handleUploadFieldChange
                }
                disabled={
                  isBusy ||
                  !editable
                }
                maxLength={180}
                placeholder="Example: Master of Science Certificate"
              />

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

          <div className="form-group">
            <label htmlFor="document">
              Select File
              <span className="required-mark">
                *
              </span>
            </label>

            <input
              ref={fileInputRef}
              id="document"
              name="document"
              type="file"
              accept=".pdf,.jpg,.jpeg,.png,application/pdf,image/jpeg,image/png"
              onChange={
                handleFileChange
              }
              disabled={
                isBusy ||
                !editable
              }
            />

            {uploadForm.document && (
              <small className="field-help">
                Selected:{" "}
                {
                  uploadForm
                    .document.name
                }{" "}
                (
                {formatFileSize(
                  uploadForm
                    .document.size
                )}
                )
              </small>
            )}

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

          <button
            type="button"
            className="primary-button document-upload-button"
            onClick={handleUpload}
            disabled={
              isBusy ||
              !editable
            }
          >
            {uploading
              ? "Uploading..."
              : "Upload document"}
          </button>
        </section>
      )}

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

      {documents.length > 0 && (
        <section className="uploaded-documents">
          <div className="uploaded-documents__heading">
            <div>
              <h3>
                Uploaded Documents
              </h3>

              <p>
                {documents.length}{" "}
                document
                {documents.length === 1
                  ? ""
                  : "s"}{" "}
                uploaded.
              </p>
            </div>
          </div>

          <div className="uploaded-document-list">
            {documents.map(
              (document) => (
                <article
                  className="uploaded-document-card"
                  key={document.id}
                >
                  <div className="uploaded-document-card__details">
                    <span className="document-type-label">
                      {getDocumentTypeLabel(
                        document.document_type
                      )}
                    </span>

                    <h4>
                      {document.document_title ||
                        document.original_file_name}
                    </h4>

                    <p>
                      {
                        document.original_file_name
                      }
                    </p>

                    <small>
                      {formatFileSize(
                        document.file_size_bytes
                      )}
                    </small>
                  </div>

                  <div className="uploaded-document-card__actions">
                    <button
                      type="button"
                      className="secondary-button"
                      onClick={() =>
                        handleDownload(
                          document
                        )
                      }
                      disabled={isBusy}
                    >
                      {processingDocumentId ===
                      document.id
                        ? "Processing..."
                        : "Download"}
                    </button>

                    <button
                      type="button"
                      className="danger-text-button"
                      onClick={() =>
                        handleDelete(
                          document
                        )
                      }
                      disabled={
                        isBusy ||
                        !editable
                      }
                    >
                      Remove
                    </button>
                  </div>
                </article>
              )
            )}
          </div>
        </section>
      )}

      {requiresDocumentUpload && (
        <div className="information-banner">
          Select a file and click{" "}
          <strong>
            Upload document
          </strong>
          . Wait until the document appears
          under Uploaded Documents before
          continuing.
        </div>
      )}

      {hasNewDocuments === "no" && (
        <div className="information-banner">
          You have indicated that you do not
          have new supporting documents. You
          may save and continue to the final
          declaration.
        </div>
      )}

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

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

        <button
          type="button"
          className="primary-button"
          onClick={() =>
            submitDocumentsSection({
              markCompleted: true
            })
          }
          disabled={
            isBusy ||
            !editable ||
            requiresDocumentUpload
          }
        >
          {saving
            ? "Saving..."
            : "Save and continue"}
        </button>
      </div>
    </div>
  );
};

export default Documents;