import { useEffect, useState } from "react";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import { toast } from "sonner";
import { useQueryClient } from "@tanstack/react-query";

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 ApproveRecordModal from "../approveRecord";
import {
  CreateOrEditLetter,
  normalizePreferredLanguage,
} from "../common/formSchema";
import { useTranslation } from "react-i18next";
import {
  deleteAttachmentsById,
  fetchRecordById,
  regeneratePdf,
  updateAndSubmitRecord,
  updateSubmitAndSendToRoRecord,
  updateAndSubmitDirectRecord,
} from "@/record-management/services/api/userRecordService";

import FileList, {
  IAttachmentInfoWithId,
} from "@/record-management/common/fileListComponent";
import {
  AttachmentInfo,
  RecordPayload,
} from "@/record-management/dto/userRecords/userRecordsDto";
import useSettings from "../../hooks/useSettings";
import { TreeViewItem } from "@/shared/common/ui/treeSelect";
import { useErrorHandler } from "@/shared/hooks/useErrorHandler";
import DelegationView from "@/record-management/common/DelegationView";
import { useAuthUser } from "@/shared/hooks/useAuthUser";
import { useUnitConfiguration } from "@/shared/hooks/useUnitConfiguration";
import {
  UploadKeyResponse,
  uploadMultiple,
  uploadSingle,
} from "@/record-management/services/api/newFileService";
import { useSignatureListWithPresigned } from "../../hooks/useSignatureAndTeeterWithPresigned";
import WorkflowCommentHistory from "@/record-management/common/WorkflowCommentHistory";

export const EditUserRecords = () => {
  const { id: recordIdFromRoute } = useParams<{ id: string }>();
  const navigate = useNavigate();
  const queryClient = useQueryClient();

  const invalidateRecordLists = () => {
    queryClient.invalidateQueries({ queryKey: ["userRecords"] });
    queryClient.invalidateQueries({ queryKey: ["userRecords-parent"] });
    queryClient.invalidateQueries({ queryKey: ["approvalRecord"] });
    if (recordIdFromRoute) {
      queryClient.invalidateQueries({
        queryKey: ["record", recordIdFromRoute],
      });
    }
  };
  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 { allModifiedOrgs, allDepartmentUnits, currentEmployeesResponse } =
    useSettings();
  const [attachments, setAttachments] = useState<File[]>([]);
  const [dmsAttachments, setDmsAttachments] = useState<any[]>([]);
  const [uploadAttachments, setUploadedAttachments] = useState<
    IAttachmentInfoWithId[]
  >([]);
  // Attachment ids the user has clicked "delete" on but not yet committed
  // by submitting the form. Empty array means nothing is staged.
  const [pendingDeletionIds, setPendingDeletionIds] = useState<string[]>([]);

  const [updatedTreeReceivingOptions, setUpdatedTreeReceivingOptions] =
    useState<TreeViewItem[]>([]);
  const [updatedCCTreeReceivingOptions, setUpdatedCCTreeReceivingOptions] =
    useState<TreeViewItem[]>([]);
  const [updatedFYRTreeReceivingOptions, setUpdatedFYRTreeReceivingOptions] =
    useState<TreeViewItem[]>([]);

  const [recordData, setRecordData] = useState<CreateOrEditLetter | null>(null);
  const [fullApiResponse, setFullApiResponse] = useState<any>(null);
  const [recordContentId, setRecordContentId] = useState<string | null>(null);
  const [isLoadingRecord, setIsLoadingRecord] = useState(true);
  const { t } = useTranslation();

  // Show the workflow comment history above the form when this outgoing
  // record came back for adjustment, so the editor sees what the reviewer
  // asked them to change.
  const isAdjustmentStatus = fullApiResponse?.statusKey === "Adjustment";
  const { editRecord } = useUserRecords();
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [approveTarget, setApproveTarget] = useState<{
    id: string;
    payload: RecordPayload;
    unitId: string;
    recordTypeKey: string;
  } | null>(null);
  const location = useLocation();
  const [remountKey, setRemountKey] = useState(0);
  const { handleError } = useErrorHandler(t);
  // Decide where Save / Forward / Approve should return the user.
  // `state.returnUrl` (set by the Approval tab's row action) wins, then we
  // honor the `?from=` query param introduced for the Collaboration / Approval
  // entry points, finally falling back to the Outgoing list.
  const fromParam = new URLSearchParams(location.search).get("from");
  const queryParamReturnUrl =
    fromParam === "collaborations"
      ? "/record-management/collaborations"
      : fromParam === "approval"
        ? "/record-management/approval"
        : null;
  const fallbackReturnUrl =
    queryParamReturnUrl ?? "/record-management/userRecords";
  useEffect(() => {
    setRemountKey((prev) => prev + 1);
  }, [location.key]);
  const load = async () => {
    try {
      setIsLoadingRecord(true);
      const res = await fetchRecordById(recordIdFromRoute!);
      const content = res?.content?.[0];
      if (!res || !content) throw new Error("Record or content not found");

      // Extract receiving units
      const receivingUnitsRaw = [...(res.receivingUnits || [])].sort(
        (a: any, b: any) => (a?.order ?? 0) - (b?.order ?? 0),
      );
      const receivingUnits = receivingUnitsRaw.map((ru) => ru.unitId);
      const nonSmartReceivers = [...(content.nonSmartReceivers || [])]
        .filter(
          (item) => item.isCc !== true || item.isForYourReference === true,
        )
        .sort((a: any, b: any) => (a?.order ?? 0) - (b?.order ?? 0));
      const nonSmartReceiverCCs = [...(content.nonSmartReceivers || [])]
        .filter((item) => item.isCc === true)
        .sort((a: any, b: any) => (a?.order ?? 0) - (b?.order ?? 0));

      // ============ FIX 1: Properly extract FYR data from API ============
      // Extract FYR from both res.forYourReferenceList and content.ccs
      const apiForYourReferenceGroups = res.forYourReferenceList ?? [];
      let forYourReferenceList: ReceiverGroup[] = [];

      if (apiForYourReferenceGroups.length > 0) {
        // Use API groups if available
        forYourReferenceList = apiForYourReferenceGroups.map((group: any) => ({
          prefix: group.prefix ?? "",
          suffix: group.suffix ?? "",
          receivers: [
            ...(group.receivers ?? [])
              .filter((r: any) => {
                const type = r.type;
                return (
                  type === "unit" || type === "non_smart" || type === "external"
                );
              })
              .map((r: any) => {
                const apiReceiver = r as any & {
                  unit?: { name?: { am?: string; en?: string } };
                };
                return {
                  unitId: r.unitId ?? undefined,
                  name: r.unitId
                    ? {
                        en:
                          apiReceiver.unit?.name?.en ||
                          apiReceiver.unit?.name?.am ||
                          r.unitId,
                        am:
                          apiReceiver.unit?.name?.am ||
                          apiReceiver.unit?.name?.en ||
                          r.unitId,
                      }
                    : r.name || "",
                  type: r.unitId ? ("unit" as const) : ("non_smart" as const),
                };
              }),
            ...((group as any).nonSmartReceivers ?? []).map((item: any) => ({
              name:
                typeof item === "string"
                  ? item
                  : (item?.name ?? item?.value ?? ""),
              type: "non_smart" as const,
            })),
          ],
        }));
      } else {
        // Fallback: extract from content.ccs where isForYourReference is true
        const fyrGroupMap = new Map<string, ReceiverGroup>();
        const fyrItems = (content.ccs || []).filter(
          (c: any) => c.isForYourReference === true,
        );

        fyrItems.forEach((item: any) => {
          const key = `${item.prefix ?? ""}||${item.suffix ?? ""}`;
          const existing = fyrGroupMap.get(key);
          const receiver: ReceiverGroupItem = item.unitId
            ? {
                unitId: item.unitId,
                name: {
                  en: item.unit?.name?.en || item.unitId || "",
                  am: item.unit?.name?.am || item.unitId || "",
                },
                type: "unit",
              }
            : {
                name: item.name || "",
                type: "non_smart",
              };

          if (existing) {
            existing.receivers.push(receiver);
          } else {
            fyrGroupMap.set(key, {
              prefix: item.prefix ?? "",
              suffix: item.suffix ?? "",
              receivers: [receiver],
            });
          }
        });

        forYourReferenceList =
          fyrGroupMap.size > 0
            ? Array.from(fyrGroupMap.values())
            : [{ prefix: "", suffix: "", receivers: [] }];
      }

      // ============ FIX 2: Extract FYR unit IDs for tree selection ============
      const fyrUnitIds = new Set<string>();
      forYourReferenceList.forEach((group) => {
        group.receivers.forEach((receiver) => {
          if (receiver.type === "unit" && receiver.unitId) {
            fyrUnitIds.add(receiver.unitId);
          }
        });
      });

      // ============ FIX 3: Build FYR tree options with proper checked state ============
      const updatedFYRTreeReceivingOptions2 = allModifiedOrgs.map((org) => {
        const isOrgSelected = fyrUnitIds.has(org.id);
        const updatedChildren =
          org.children?.map((child) => ({
            ...child,
            checked: fyrUnitIds.has(child.id),
          })) || [];

        const allChildrenChecked =
          updatedChildren.length > 0
            ? updatedChildren.every((child) => child.checked)
            : false;
        const someChildrenChecked = updatedChildren.some(
          (child) => child.checked,
        );

        let checkedState: boolean | "indeterminate" = false;
        if (isOrgSelected) {
          checkedState = true;
        } else if (allChildrenChecked) {
          checkedState = true;
        } else if (someChildrenChecked) {
          checkedState = "indeterminate";
        }

        return {
          ...org,
          checked: checkedState,
          children: updatedChildren,
        };
      });

      // ============ FIX 4: Build checked FYR units (same pattern as externalCC) ============
      const checkedFYRUnits: TreeViewItem[] =
        updatedFYRTreeReceivingOptions2.flatMap((org) => {
          const items: TreeViewItem[] = [];

          // Include org itself if it's checked
          if (org.checked === true) {
            items.push({
              id: org.id,
              name: org.name,
              checked: true,
              hierarchyType: org.hierarchyType,
              children: [],
            });
          }

          // Include all checked children
          if (org.children?.length) {
            const checkedChildren = org.children
              .filter((child) => child.checked === true)
              .map((child) => ({
                id: child.id,
                name: child.name,
                checked: true,
                hierarchyType: child.hierarchyType,
                children: [],
              }));
            items.push(...checkedChildren);
          }

          return items;
        });

      // Build receiver groups (same as before)
      type ReceiverGroupItem = {
        unitId?: string;
        name?: string | { en: string; am: string };
        type: "unit" | "non_smart";
      };
      type ReceiverGroup = {
        prefix: string;
        suffix: string;
        receivers: ReceiverGroupItem[];
      };

      const buildGroupKey = (prefix: string, suffix: string) =>
        `${prefix}||${suffix}`;
      const receiverGroupMap = new Map<string, ReceiverGroup>();

      const defaultPrefix = content.prefix ?? "";
      const defaultSuffix = content.suffix ?? "";

      receivingUnitsRaw.forEach((ru: any) => {
        const key = buildGroupKey(
          ru.prefix ?? defaultPrefix,
          ru.suffix ?? defaultSuffix,
        );
        const existing = receiverGroupMap.get(key);
        const receiver = {
          unitId: ru.unitId,
          name: {
            en: ru.unit?.name?.en || ru.unit?.name?.am || ru.unitId || "",
            am: ru.unit?.name?.am || ru.unit?.name?.en || ru.unitId || "",
          },
          type: "unit" as const,
        };

        if (existing) {
          existing.receivers.push(receiver);
        } else {
          receiverGroupMap.set(key, {
            prefix: ru.prefix ?? defaultPrefix,
            suffix: ru.suffix ?? defaultSuffix,
            receivers: [receiver],
          });
        }
      });

      nonSmartReceivers.forEach((item: any) => {
        const key = buildGroupKey(
          item.prefix ?? defaultPrefix,
          item.suffix ?? defaultSuffix,
        );
        const existing = receiverGroupMap.get(key);
        const receiver = {
          name: item.name,
          type: "non_smart" as const,
        };

        if (existing) {
          existing.receivers.push(receiver);
        } else {
          receiverGroupMap.set(key, {
            prefix: item.prefix ?? defaultPrefix,
            suffix: item.suffix ?? defaultSuffix,
            receivers: [receiver],
          });
        }
      });

      const receiversList: ReceiverGroup[] =
        receiverGroupMap.size > 0
          ? Array.from(receiverGroupMap.values())
          : [{ prefix: defaultPrefix, suffix: defaultSuffix, receivers: [] }];

      // Build CC list (same as before, keep existing logic)
      const apiCcGroups = res.ccList ?? content.ccList ?? [];
      const ccList = apiCcGroups.map((group: any) => ({
        prefix: group.prefix ?? "",
        suffix: group.suffix ?? "",
        receivers: [
          ...(group.receivers ?? [])
            .filter((r: any) => {
              const t = (r as { type?: string }).type;
              return t !== "internal";
            })
            .map((r: any) => {
              const apiReceiver = r as typeof r & {
                unit?: { name?: { am?: string; en?: string } };
                position?: { name?: { am?: string; en?: string } };
              };
              const displayName =
                apiReceiver.unit?.name?.am ||
                apiReceiver.unit?.name?.en ||
                apiReceiver.position?.name?.am ||
                apiReceiver.position?.name?.en ||
                r.name ||
                r.unitId ||
                "";
              return {
                id: r.id ?? undefined,
                unitId: r.unitId ?? undefined,
                positionId: r.positionId ?? undefined,
                name: r.unitId
                  ? {
                      en:
                        apiReceiver.unit?.name?.en ||
                        apiReceiver.unit?.name?.am ||
                        apiReceiver.position?.name?.en ||
                        apiReceiver.position?.name?.am ||
                        displayName,
                      am:
                        apiReceiver.unit?.name?.am ||
                        apiReceiver.unit?.name?.en ||
                        apiReceiver.position?.name?.am ||
                        apiReceiver.position?.name?.en ||
                        displayName,
                    }
                  : displayName || undefined,
                type: r.unitId ? ("unit" as const) : ("non_smart" as const),
              };
            }),
          ...((group as any).nonSmartReceivers ?? []).map((item: any) => ({
            id: item?.id ?? undefined,
            name:
              typeof item === "string"
                ? item
                : (item?.name ?? item?.value ?? undefined),
            type: "non_smart" as const,
          })),
        ],
      }));

      // Extract CC unit IDs for tree
      const ccReceivingUnits = (content.ccs || [])
        .filter((c) => c.type === "external")
        .map((c) => c.unitId)
        .filter(Boolean);

      const updatedCCTreeReceivingOptions2 = allModifiedOrgs.map((org) => {
        const isOrgSelected = ccReceivingUnits.includes(org.id);
        const updatedChildren =
          org.children?.map((child) => ({
            ...child,
            checked: ccReceivingUnits.includes(child.id),
          })) || [];

        const allChildrenChecked =
          updatedChildren.length > 0
            ? updatedChildren.every((child) => child.checked)
            : false;
        const someChildrenChecked = updatedChildren.some(
          (child) => child.checked,
        );

        let checkedState: boolean | "indeterminate" = false;
        if (isOrgSelected) {
          checkedState = true;
        } else if (allChildrenChecked) {
          checkedState = true;
        } else if (someChildrenChecked) {
          checkedState = "indeterminate";
        }

        return {
          ...org,
          checked: checkedState,
          children: updatedChildren,
        };
      });

      const checkedCCUnits: TreeViewItem[] =
        updatedCCTreeReceivingOptions2.flatMap((org) => {
          const items: TreeViewItem[] = [];
          if (org.checked === true) {
            items.push({
              id: org.id,
              name: org.name,
              checked: true,
              hierarchyType: org.hierarchyType,
              children: [],
            });
          }
          if (org.children?.length) {
            const checkedChildren = org.children
              .filter((child) => child.checked === true)
              .map((child) => ({
                id: child.id,
                name: child.name,
                checked: true,
                hierarchyType: child.hierarchyType,
                children: [],
              }));
            items.push(...checkedChildren);
          }
          return items;
        });

      // Build receiving units tree
      const receivingUnitsTree: TreeViewItem[] = receivingUnitsRaw.map(
        (ru: any) => ({
          id: ru.unitId,
          name: {
            en: ru.unit?.name?.en || ru.unitId || "",
            am: ru.unit?.name?.am || ru.unitId || "",
          },
          hierarchyType: "unit",
          value: ru.unitId,
          children: [],
          checked: true,
        }),
      );

      const updatedTreeReceivingOptions2 = allModifiedOrgs.map((org) => {
        const isOrgSelected = receivingUnits.includes(org.id);
        const updatedChildren =
          org.children?.map((child) => ({
            ...child,
            checked: receivingUnits.includes(child.id),
          })) || [];

        const allChildrenChecked =
          updatedChildren.length > 0
            ? updatedChildren.every((child) => child.checked)
            : false;
        const someChildrenChecked = updatedChildren.some(
          (child) => child.checked,
        );

        let checkedState: boolean | "indeterminate" = false;
        if (isOrgSelected) {
          checkedState = true;
        } else if (allChildrenChecked) {
          checkedState = true;
        } else if (someChildrenChecked) {
          checkedState = "indeterminate";
        }

        return {
          ...org,
          checked: checkedState,
          children: updatedChildren,
        };
      });

      const sortedReceiverEmployees = [
        ...(content.receiverEmployees || []),
      ].sort((a: any, b: any) => (a?.order ?? 0) - (b?.order ?? 0));
      const sortedReceiverPositions = [
        ...(content.receiverPositions || []),
      ].sort((a: any, b: any) => (a?.order ?? 0) - (b?.order ?? 0));

      const collaboratorPositionIds = (res.collaborators || [])
        .map((c) => c.employeePositionId)
        .filter((id): id is string => Boolean(id));

      const resolvedInitiationType =
        res.initiationType ||
        (res.isWithTeamSignature ? "team" : "") ||
        res.initiatedAs ||
        "self";

      // ============ FIX 5: Set form data with proper FYR values ============
      setRecordData({
        body: content.body,
        footerId: content.footerId ?? "",
        headerId: content.headerId ?? "",
        initiationType: resolvedInitiationType,
        preferredLanguage: normalizePreferredLanguage(res.preferredLanguage),
        receivingUnitIds: receivingUnitsTree,
        recordType: res.recordTypeKey,
        sincerelyText: content.sincerelyText,
        subject: content.subject,
        referenceNumber: res.referenceNumber ?? "",
        internalCC: (content.ccs || [])
          .filter(
            (c) =>
              c.type === "internal" &&
              c.employeePositionId === null &&
              !c.isForYourReference,
          )
          .map((c) => c.positionId),
        externalCC: checkedCCUnits,
        collaborators: collaboratorPositionIds,
        recordTemplateId: content.recordTemplateId ?? "",
        toEmployees: sortedReceiverEmployees.map((rp) => rp.employeePositionId),
        ccEmployees: (content?.ccs || [])
          .filter((c) => c.employeePositionId !== null && !c.isForYourReference)
          .map((rp) => rp.employeePositionId),
        toPositions: sortedReceiverPositions.map((rp) => rp.positionId),
        prefix: content.prefix ?? "",
        suffix: content.suffix ?? "",
        ccPrefix: content.prefixCC ?? "",
        ccSuffix: content.suffixCC ?? "",
        ReceiversList: receiversList,
        ReceiverList: receiversList,
        ccList,
        // ============ FIX 6: Include forYourReferenceList in form data ============
        forYourReferenceList: forYourReferenceList,
        groupedItems: [
          {
            prefix: content.prefix ?? "",
            suffix: content.suffix ?? "",
            values: nonSmartReceivers.map((rs: any) => rs.name),
          },
        ],
        groupedCCItems: [
          {
            prefix: content.prefixCC ?? "",
            suffix: content.suffixCC ?? "",
            values: nonSmartReceiverCCs.map((rs: any) => rs.name),
          },
        ],
        groupedTreeItems: [
          {
            prefix: content.prefix ?? "",
            suffix: content.suffix ?? "",
            values: receivingUnitsTree,
          },
        ],
        groupedCCTreeItems: [
          {
            prefix: content.prefixCC ?? "",
            suffix: content.suffixCC ?? "",
            values: checkedCCUnits,
          },
        ],
        // ============ FIX 7: Include FYR legacy fields ============
        groupedFYRTreeItems: [
          {
            prefix: content.prefixCC ?? "",
            suffix: content.suffixCC ?? "",
            values: checkedFYRUnits,
          },
        ],
        groupedFYRItems: forYourReferenceList.map((group) => ({
          prefix: group.prefix,
          suffix: group.suffix,
          values: group.receivers
            .filter((r) => r.type === "non_smart")
            .map((r) =>
              typeof r.name === "string" ? r.name : r.name?.en || "",
            ),
        })),
        isWithTeamSignature: res.isWithTeamSignature,
        skipOneLevel: res.skipOneLevel ?? content.skipOneLevel ?? false,
        letterName: res.letterName,
        nonSmartOfficeReceiverCCs: nonSmartReceiverCCs.map(
          (rs: any) => rs.name,
        ),
        nonSmartOfficeReceivers: nonSmartReceivers.map((rs: any) => rs.name),
        mode: "edit",
        recordTagIds: (content.recordTagRecords || []).map(
          (r) => r.recordTagId,
        ),
        initiatedAs: res.initiatedAs || res.initiationType || "",
        forYourReference: (content.ccs || [])
          .filter((c) => c.isForYourReference === true && c.positionId)
          .map((c) => c.positionId),
        // ============ FIX 8: Include FYR unit IDs ============
        forYourReferenceUnitIds: checkedFYRUnits,
      } as CreateOrEditLetter);

      setRecordContentId(content.id);
      setFullApiResponse(res);
      setUpdatedTreeReceivingOptions(updatedTreeReceivingOptions2);
      setUpdatedCCTreeReceivingOptions(updatedCCTreeReceivingOptions2);
      setUpdatedFYRTreeReceivingOptions(updatedFYRTreeReceivingOptions2);

      setUploadedAttachments(content?.recordAttachments || []);
    } catch (error) {
      await handleError(error);
    } finally {
      setIsLoadingRecord(false);
    }
  };

  useEffect(() => {
    if (!recordIdFromRoute || !allModifiedOrgs?.length) return;
    load();
  }, [recordIdFromRoute, allModifiedOrgs.length]);

  const handleFormSubmit = async (
    values: CreateOrEditLetter,
    intent: RecordFormIntent = "draft",
  ): Promise<void> => {
    setIsSubmitting(true);

    try {
      if (!recordIdFromRoute || !recordContentId) {
        throw new Error("Missing record ID or content ID");
      }

      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.
      // The receivingPositionIds check still excludes positions that are
      // also direct recipients — same as the previous filter.
      const internalCCValues =
        (values.internalCC ?? [])
          .filter((id) => !receivingPositionIds.includes(id))
          .map((id) => allDepartmentUnits?.find((u) => u.id === id))
          .filter((u): u is NonNullable<typeof u> => u != null) ?? [];

      // 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. The receivingEmployeeIds check still excludes
      // employees that are also direct recipients — same as the previous
      // filter.
      const ccEmployee =
        (values.ccEmployees ?? [])
          .filter((id) => !receivingEmployeeIds.includes(id))
          .map((employeePositionId) =>
            currentEmployeesResponse?.items?.find(
              (employee) =>
                employee.employeePositions?.[0]?.id === employeePositionId,
            ),
          )
          .filter(
            (employee): employee is NonNullable<typeof employee> =>
              employee != null,
          ) ?? [];

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

      // =========================
      // 2. NORMALIZE EXISTING ATTACHMENTS (OLD + NEW)
      // =========================
      const existingAttachments: AttachmentInfo[] = (
        values?.attachments || []
      ).map((att: any) => {
        // already new format
        if (att.fileInfo) return att;

        // old format → convert
        return {
          fileInfo: {
            bucket: att.bucket || "",
            fileName: att.fileName || att.name,
            contentType: att.contentType || "application/octet-stream",
            originalname: att.originalname || att.fileName || att.name,
            size: att.size || 0,
          },
          name: {
            am: att.originalname || att.fileName || att.name,
            en: att.originalname || att.fileName || att.name,
          },
        };
      });

      // =========================
      // 3. UPLOAD NEW FILES ONLY
      // =========================
      let newUploaded: UploadKeyResponse["fileInfo"][] = [];

      if (attachments?.length > 1) {
        newUploaded = await uploadMultiple(attachments);
      } else if (attachments?.length === 1) {
        const file = await uploadSingle(attachments[0]);
        newUploaded = [file];
      }

      const newAttachments: AttachmentInfo[] = newUploaded.map((f) => ({
        fileInfo: f,
        name: {
          am: f.originalname,
          en: f.originalname,
        },
      }));

      // =========================
      // 4. MERGE FINAL ATTACHMENTS
      // =========================
      const dmsAttachmentsMapped: AttachmentInfo[] = dmsAttachments.map(
        (doc: any) => ({
          fileInfo: {
            bucket: doc.fileInfo?.bucket || "",
            fileName: doc.fileInfo?.fileName || doc.fileInfo?.originalname || "",
            contentType: doc.fileInfo?.contentType || "application/octet-stream",
            originalname:
              doc.fileInfo?.originalname ||
              doc.name?.en ||
              doc.name?.am ||
              "",
            size: doc.fileInfo?.size || 0,
          },
          name: {
            am: doc.name?.am || doc.name?.en || doc.fileInfo?.originalname || "",
            en: doc.name?.en || doc.name?.am || doc.fileInfo?.originalname || "",
          },
        }),
      );

      const finalAttachments: AttachmentInfo[] = [
        ...existingAttachments,
        ...newAttachments,
        ...dmsAttachmentsMapped,
      ];

      // =========================
      // 5. 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, CC employees, For-Your-Reference,
      // and the receivers inside each ccList group (external CC).
      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,
            })) ?? []),

          ...(ccEmployee
            ?.slice()
            // .reverse()
            .map((c) => ({
              positionId: c.employeePositions[0]?.position?.id,
              employeePositionId: c.employeePositions[0]?.id,
              type: "internal" as const,
            })) ?? []),
          ...forYourReferenceValues
            .slice()
            // .reverse()
            .map((c) => ({
              unitId: c.unitId!,
              positionId: c.id!,
              type: "internal" as const,
              isForYourReference: true,
            })),
        ],
        headerId:
          values.recordType === "direct" &&
          unitConfig?.shouldDirectRecordHaveHeaderAndFooter === false
            ? null
            : values.headerId,
        footerId:
          values.recordType === "direct" &&
          unitConfig?.shouldDirectRecordHaveHeaderAndFooter === false
            ? null
            : values.footerId,
        receiverList: receiversList.map(serializeReceiverGroup),
        ccList: ccList.map(serializeReceiverGroup).map((g) => ({
          ...g,
          receivers: g.receivers.slice(),
          // .reverse()
        })),
        forYourReferenceList: forYourReferenceList
          .map(serializeReceiverGroup)
          .map((g) => ({
            ...g,
            receivers: g.receivers.slice(),
          })),
        receivingUnitIds,
        nonSmartOfficeReceivers: values.nonSmartOfficeReceivers ?? [],
        nonSmartOfficeReceiverCCs: values.nonSmartOfficeReceiverCCs ?? [],
        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,
        letterName: values.letterName ?? "",
        isWithTeamSignature: values?.isWithTeamSignature,
        skipOneLevel: values.skipOneLevel ?? false,
        recordTagIds: values.recordTagIds,
        inReplyToIncomingInstanceId: values.inReplyToIncomingInstanceId,
        initiatedAs: values.initiatedAs || "",
        attachments: finalAttachments,
      };

      // ─── Approve intent: defer to ApproveRecordModal ─────────
      // The modal collects stamp/signature/etc., then dispatches the combined
      // update-submit-and-send-to-RO endpoint via its onCustomSubmit. Pending
      // attachment deletions are committed inside the modal's flow.
      if (intent === "approve") {
        setApproveTarget({
          id: recordIdFromRoute,
          payload,
          unitId: userDetails?.employee?.[0]?.unitId ?? "",
          recordTypeKey: values.recordType,
        });
        return;
      }

      // ─── Forward / Direct intents ─────────
      if (intent === "forward") {
        await updateAndSubmitRecord(recordIdFromRoute, payload);
      } else if (intent === "direct") {
        const signatureId = signatureData?.signatureId;
        if (!signatureId) {
          toast.error(t("userRecord.noSignatureForDirectSend"));
          return;
        }
        await updateAndSubmitDirectRecord(recordIdFromRoute, {
          payload,
          signatureId,
        });
      } else {
        // ─── Draft intent (default): plain update ────────────
        await editRecord({
          id: recordIdFromRoute,
          updatedRecord: payload,
        });
      }

      // Commit staged attachment deletions now that the record update succeeded.
      if (pendingDeletionIds.length > 0) {
        const deletionResults = await Promise.allSettled(
          pendingDeletionIds.map((id) => deleteAttachmentsById(id)),
        );
        const firstFailure = deletionResults.find(
          (r): r is PromiseRejectedResult => r.status === "rejected",
        );
        if (firstFailure) {
          await handleError(firstFailure.reason);
        }
        setPendingDeletionIds([]);
      }

      const returnUrl = location.state?.returnUrl || fallbackReturnUrl;
      const recordId = location.state?.recordId;

      // Regenerate PDF if returning to approval page
      if (recordId && returnUrl === "/record-management/approval") {
        try {
          await regeneratePdf(recordId);
          queryClient.invalidateQueries({ queryKey: ["record-pdf", recordId] });
          queryClient.invalidateQueries({ queryKey: ["record", recordId] });
        } catch (regenerateError) {
          await handleError(regenerateError);
          // Don't block navigation if regeneration fails
        }
      }

      // Invalidate related lists so the user sees the change in any tab.
      invalidateRecordLists();

      if (intent === "forward") {
        toast.success(t("userRecord.recordUpdatedAndForwarded"));
      } else {
        // After-submit attachment count = retained existing + newly-uploaded.
        const retainedExistingCount =
          (uploadAttachments?.length ?? 0) - pendingDeletionIds.length;
        const finalAttachmentCount = retainedExistingCount + attachments.length;
        toast.success(
          finalAttachmentCount > 0
            ? t("msg.submittedWithAttachments")
            : t("msg.submittedSuccess"),
        );
      }
      navigate(returnUrl);
    } catch (submitError) {
      await handleError(submitError);
    } finally {
      setIsSubmitting(false);
    }
  };

  // Stage the deletion locally; the actual DELETE request is fired only
  // after the user confirms the change by clicking submit and the record
  // update succeeds. If they navigate away or refresh, nothing is lost.
  const handleAttachmentDelete = (fileId: string) => {
    setPendingDeletionIds((prev) =>
      prev.includes(fileId) ? prev : [...prev, fileId],
    );
  };

  const visibleUploadAttachments = (uploadAttachments || []).filter(
    (attachment) =>
      !attachment.id || !pendingDeletionIds.includes(attachment.id),
  );

  return isDelegated ? (
    <DelegationView />
  ) : (
    <div className="w-full max-w-5xl mx-auto">
      <div className="pb-2 text-xl font-bold">{t("addRecord.EditRecord")}</div>

      {isAdjustmentStatus && recordIdFromRoute && (
        <div className="mb-4">
          <WorkflowCommentHistory recordId={recordIdFromRoute} />
        </div>
      )}

      <RecordForm
        key={remountKey}
        onSubmit={handleFormSubmit}
        recordId={recordIdFromRoute}
        defaultValues={recordData}
        fullApiResponse={fullApiResponse}
        isEditMode={true}
        isLoading={isSubmitting}
        isLoadingRecord={isLoadingRecord}
        existingAttachmentComponent={
          <div className="max-w-4xl mx-auto">
            <FileList
              attachments={visibleUploadAttachments}
              showDelete={true}
              onDelete={handleAttachmentDelete}
            />
          </div>
        }
        files={attachments}
        setFiles={setAttachments}
        dmsAttachments={dmsAttachments}
        setDmsAttachments={setDmsAttachments}
        treeOrganizationsOptions={updatedTreeReceivingOptions}
        ccTreeOrganizationsOptions={updatedCCTreeReceivingOptions}
        fyrTreeOrganizationsOptions={updatedFYRTreeReceivingOptions}
      />
      {approveTarget && (
        <ApproveRecordModal
          open={!!approveTarget}
          onClose={() => setApproveTarget(null)}
          recordData={{
            unitId: approveTarget.unitId,
            recordTypeKey: approveTarget.recordTypeKey,
          }}
          onCustomSubmit={async (approvalData) => {
            await updateSubmitAndSendToRoRecord(
              approveTarget.id,
              approveTarget.payload,
              approvalData,
            );
            invalidateRecordLists();
          }}
          onSuccess={() => {
            setApproveTarget(null);
            toast.success(t("userRecord.recordUpdatedAndForwarded"));
            navigate(location.state?.returnUrl || fallbackReturnUrl);
          }}
          preferredLanguage={
            approveTarget.payload.preferredLanguage === "en" ? "en" : "am"
          }
        />
      )}
    </div>
  );
};
