"use client";
import { useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import RecordForm, { type RecordFormIntent } from "../common/recordForm";

const serializeReceiverGroup = (group: any) => ({
  prefix: group.prefix ?? "",
  suffix: group.suffix ?? "",
  receivers:
    group.receivers?.map((receiver: any) => ({
      ...receiver,
      name:
        receiver.type === "non_smart"
          ? typeof receiver.name === "string"
            ? receiver.name
            : receiver.name?.en || receiver.name?.am || ""
          : receiver.name,
    })) ?? [],
});
import { useUserRecords } from "@/record-management/components/hooks/useUserRecords";
import { recordFileService } from "@/record-management/services/api/recordFileService";
import {
  AttachmentInfo,
  RecordPayload,
} from "@/record-management/dto/userRecords/userRecordsDto";
import {
  CreateOrEditLetter,
  defaultCreateLetterValues,
} from "../common/formSchema";
import { useTranslation } from "react-i18next";
import useSettings from "../../hooks/useSettings";
import { useErrorHandler } from "@/shared/hooks/useErrorHandler";
import {
  STORAGE_UPLOAD_ERROR_CODE,
  STORAGE_UPLOAD_TOO_LARGE,
  recordFileServiceV2,
  UploadKeyResponse,
  uploadMultiple,
  uploadSingle,
} from "@/record-management/services/api/newFileService";
import {
  createAndSubmitRecord,
  createSubmitAndSendToRoRecord,
  createAndSubmitDirectRecord,
} from "@/record-management/services/api/userRecordService";
import { useAuthUser } from "@/shared/hooks/useAuthUser";
import ApproveRecordModal from "../approveRecord";
import DelegationView from "@/record-management/common/DelegationView";
import { useSignatureListWithPresigned } from "../../hooks/useSignatureAndTeeterWithPresigned";
import { useUnitConfiguration } from "@/shared/hooks/useUnitConfiguration";

export const AddUserRecords = ({ id }: { id?: string }) => {
  const navigate = useNavigate();
  const location = useLocation();
  const queryClient = useQueryClient();
  const { addRecord } = useUserRecords();

  const invalidateRecordLists = () => {
    queryClient.invalidateQueries({ queryKey: ["userRecords"] });
    queryClient.invalidateQueries({ queryKey: ["userRecords-parent"] });
    queryClient.invalidateQueries({ queryKey: ["approvalRecord"] });
  };
  const { t } = useTranslation();
  const [attachments, setAttachments] = useState<File[]>([]);
  const [dmsAttachments, setDmsAttachments] = useState<any[]>([]);
  const { handleError } = useErrorHandler(t);
  const { allModifiedOrgs, allDepartmentUnits, currentEmployeesResponse } =
    useSettings();
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [approveTarget, setApproveTarget] = useState<{
    payload: RecordPayload;
    unitId: string;
    recordTypeKey: string;
  } | null>(null);
  const { userDetails } = useAuthUser();
  const unitId = userDetails?.employee?.[0]?.unitId || "";
  const { data: signatureData } = useSignatureListWithPresigned(
    userDetails?.id || "",
  );
  const { data: unitConfigData } = useUnitConfiguration(unitId, {
    enabled: !!unitId,
  });
  const isDelegated = userDetails?.employee?.some((emp) =>
    emp.positions.some((pos) => pos.hasDelegated),
  );

  const handleFormSubmit = async (
    values: CreateOrEditLetter,
    intent: RecordFormIntent = "draft",
  ): Promise<void> => {
    setIsSubmitting(true);
    try {
      const receiversList = values.ReceiversList ?? [];
      const ccList = values.ccList ?? [];
      const forYourReferenceList = values.forYourReferenceList ?? [];
      const receivingPositionIds = values.toPositions || [];
      const receivingEmployeeIds = values.toEmployees || [];
      const receivingUnitIds = values.receivingUnitIds?.map((u) => u.id) || [];

      // Walk values.internalCC in user-selection order rather than filtering
      // allDepartmentUnits (which would re-order by directory position), so
      // the cc[] payload preserves the order the user added departments in.
      const internalCCValues =
        (values.internalCC ?? [])
          .map((id) => allDepartmentUnits?.find((u) => u.id === id))
          .filter((u): u is NonNullable<typeof u> => u != null) ?? [];

      const externalCCValues = values.externalCC ?? [];

      // Same selection-order fix as internalCCValues: walk the form arrays so
      // cc employees and for-your-reference entries appear in the order the
      // user added them rather than the underlying directory's order.
      const ccEmployee =
        (values.ccEmployees ?? [])
          .map((employeePositionId) =>
            currentEmployeesResponse?.items?.find(
              (e) => e.employeePositions?.[0]?.id === employeePositionId,
            ),
          )
          .filter((e): e is NonNullable<typeof e> => e != null) ?? [];

      const forYourReferenceValues =
        (values.forYourReference ?? [])
          .map((id) => allDepartmentUnits?.find((u) => u.id === id))
          .filter((u): u is NonNullable<typeof u> => u != null) ?? [];

      // =========================
      // 1. UPLOAD FILES (non-mutation: handle errors locally)
      // =========================
      let fileInfos: UploadKeyResponse["fileInfo"][] = [];

      try {
        if (attachments?.length > 1) {
          fileInfos = await uploadMultiple(attachments);
        } else if (attachments?.length === 1) {
          const fileInfo = await uploadSingle(attachments[0]);
          fileInfos = [fileInfo];
        }
      } catch (uploadError) {
        if (
          uploadError instanceof Error &&
          uploadError.message === STORAGE_UPLOAD_TOO_LARGE
        ) {
          toast.error(t("userRecord.storageUploadFailed"), {
            description: t("msg.fileTooLarge"),
          });
        } else if (
          uploadError instanceof Error &&
          uploadError.message === STORAGE_UPLOAD_ERROR_CODE
        ) {
          await handleError(new Error(t("userRecord.storageUploadFailed")));
        } else {
          await handleError(uploadError);
        }
        return;
      }

      // convert fileInfo → AttachmentInfo (ONLY IF REQUIRED)
      const uploadedFiles: AttachmentInfo[] = fileInfos.map((f) => ({
        fileInfo: {
          bucket: f.bucket,
          fileName: f.fileName,
          contentType: f.contentType,
          originalname: f.originalname,
          size: f.size,
        },
        name: {
          am: f.originalname,
          en: f.originalname,
        },
      }));

      // convert DMS documents → AttachmentInfo
      const dmsUploadedFiles: AttachmentInfo[] = dmsAttachments.map((doc) => ({
        fileInfo: {
          bucket: doc.fileInfo?.bucket || "",
          fileName: doc.fileInfo?.fileName || "",
          contentType: doc.fileInfo?.contentType || "",
          size: doc.fileInfo?.size || 0,
          originalname:
            doc.fileInfo?.originalname ||
            (typeof doc.name === "object" ? doc.name?.en || doc.name?.am : doc.name) ||
            "document",
        },
        name: {
          am: (typeof doc.name === "object" ? doc.name?.am || doc.name?.en : doc.name) || "document",
          en: (typeof doc.name === "object" ? doc.name?.en || doc.name?.am : doc.name) || "document",
        },
      }));

      // =========================
      // 2. BUILD PAYLOAD
      // =========================
      const unitConfig = unitConfigData?.data?.items?.[0];

      // Reverse each CC bucket before serializing. The BE renders the PDF in
      // reverse of the order we send (last entry comes out first), so flipping
      // the array here lets the BE's reversal land back on selection order.
      // Applies to: internal departments, external CC units, CC employees,
      // For-Your-Reference, and the receivers inside each ccList group.
      const payload: RecordPayload = {
        body: values.body,
        referenceNumber: values.referenceNumber,
        cc: [
          ...internalCCValues
            .slice()
            // .reverse()
            .map((c) => ({
              unitId: c.unitId!,
              positionId: c.id!,
              type: "internal" as const,
            })),
          ...externalCCValues
            .slice()
            // .reverse()
            .map((c) => ({
              unitId: c.id,
              type: "external" as const,
            })),
          ...ccEmployee.slice().map((c) => ({
            positionId: c.employeePositions[0]?.position?.id,
            employeePositionId: c.employeePositions[0]?.id,
            type: "internal" as const,
          })),
          ...forYourReferenceValues.slice().map((c) => ({
            unitId: c.unitId!,
            positionId: c.id!,
            type: "internal" as const,
            isForYourReference: true,
          })),
        ],
        receiverList: receiversList.map(serializeReceiverGroup),
        ccList: ccList.map(serializeReceiverGroup).map((g) => ({
          ...g,
          receivers: g.receivers.slice(),
        })),
        forYourReferenceList: forYourReferenceList
          .map(serializeReceiverGroup)
          .map((g) => ({
            ...g,
            receivers: g.receivers.slice(),
          })),
        nonSmartOfficeReceiverCCs: values.nonSmartOfficeReceiverCCs ?? [],
        headerId:
          values.recordType === "direct" &&
          unitConfig?.shouldDirectRecordHaveHeaderAndFooter === false
            ? null
            : values.headerId,
        footerId:
          values.recordType === "direct" &&
          unitConfig?.shouldDirectRecordHaveHeaderAndFooter === false
            ? null
            : values.footerId,
        receivingUnitIds,
        nonSmartOfficeReceivers: values.nonSmartOfficeReceivers ?? [],
        recordType: values.recordType,
        subject: values.subject,
        collaborators: values.collaborators ?? [],
        toPositions: values.toPositions ?? [],
        toEmployees: values.toEmployees ?? [],
        preferredLanguage: values.preferredLanguage as "am" | "en",
        initiationType: values.initiationType,
        sincerelyText: values.sincerelyText,
        recordTemplateId: values.recordTemplateId || undefined,
        prefix: values.prefix ?? "",
        prefixCC: values.ccPrefix ?? "",
        suffix: values.suffix ?? "",
        suffixCC: values.ccSuffix ?? "",
        isWithTeamSignature: values.isWithTeamSignature,
        skipOneLevel: values.skipOneLevel ?? false,
        letterName: values.letterName,
        recordTagIds: values.recordTagIds,
        initiatedAs: values.initiatedAs || values.initiationType || "",
        inReplyToIncomingInstanceId: id,

        attachments: [...uploadedFiles, ...dmsUploadedFiles],
      };

      // =========================
      // 3. SEND PAYLOAD ACCORDING TO INTENT (mutation: errors already toasted by addMutation.onError)
      // =========================
      if (intent === "forward") {
        await createAndSubmitRecord(payload);
        invalidateRecordLists();
        toast.success(t("userRecord.recordCreatedAndForwarded"));
        navigate("/record-management/userRecords");
      } else if (intent === "direct") {
        const signatureId = signatureData?.signatureId;
        if (!signatureId) {
          toast.error(t("userRecord.noSignatureForDirectSend"));
          return;
        }
        await createAndSubmitDirectRecord({ payload, signatureId });
        invalidateRecordLists();
        toast.success(t("userRecord.recordCreatedAndSent"));
        navigate("/record-management/userRecords");
      } else if (intent === "approve") {
        // Defer the create call — the approval modal will collect stamp/
        // signature/etc. and then dispatch the combined endpoint.
        setApproveTarget({
          payload,
          unitId: userDetails?.employee?.[0]?.unitId ?? "",
          recordTypeKey: values.recordType,
        });
      } else {
        let created;
        try {
          created = await addRecord(payload);
        } catch {
          return;
        }
        if (!created?.id) {
          await handleError(new Error(t("msg.genericError")));
          return;
        }
        invalidateRecordLists();
        toast.success(
          attachments.length > 0 || dmsAttachments.length > 0
            ? t("msg.submittedWithAttachments")
            : t("msg.submittedSuccess"),
        );
        navigate("/record-management/userRecords");
      }
    } finally {
      setIsSubmitting(false);
    }
  };

  return isDelegated ? (
    <DelegationView />
  ) : (
    <div className="w-full max-w-5xl mx-auto">
      <div className="pb-2 text-xl font-bold">{t("userRecord.Add Record")}</div>
      <RecordForm
        key={location.key}
        onSubmit={handleFormSubmit}
        defaultValues={defaultCreateLetterValues}
        isEditMode={false}
        isLoading={isSubmitting}
        setFiles={setAttachments}
        files={attachments}
        dmsAttachments={dmsAttachments}
        setDmsAttachments={setDmsAttachments}
        treeOrganizationsOptions={allModifiedOrgs ?? []}
        ccTreeOrganizationsOptions={allModifiedOrgs ?? []}
        fyrTreeOrganizationsOptions={allModifiedOrgs ?? []}
      />
      {approveTarget && (
        <ApproveRecordModal
          open={!!approveTarget}
          onClose={() => setApproveTarget(null)}
          recordData={{
            unitId: approveTarget.unitId,
            recordTypeKey: approveTarget.recordTypeKey,
            referenceNumber: approveTarget.payload.referenceNumber,
          }}
          onCustomSubmit={async (approvalData) => {
            await createSubmitAndSendToRoRecord(
              approveTarget.payload,
              approvalData,
            );
            invalidateRecordLists();
          }}
          onSuccess={() => {
            setApproveTarget(null);
            toast.success(t("userRecord.recordCreatedAndForwarded"));
            navigate("/record-management/userRecords");
          }}
          preferredLanguage={
            approveTarget.payload.preferredLanguage === "en" ? "en" : "am"
          }
        />
      )}
    </div>
  );
};
