import { useCallback } from 'react';
import { assignCorrespondentsBulk } from '../../lib/apiClient';
import type { Identifier } from '../../types/identifiers';

type BulkAssignmentResponse = {
  assigned?: number;
  removed?: number;
};

type CorrespondentAssignment = {
  correspondent_id?: Identifier;
};

interface UseBulkDocumentActionsArgs {
  resolveTargetDocumentIds: (ids?: Identifier[] | null) => Identifier[];
  correspondentLookupByName: Map<string, { id?: Identifier }>;
  handleCorrespondentCreate: (payload: { name: string }) => Promise<{ id?: Identifier } | null>;
  setStatusMessage: (message: string, variant?: string) => void;
  selectedDocumentIds?: Identifier[];
  selectedFolderIds?: Identifier[];
  handleDocumentsDelete: (ids: Identifier[], options?: { showMessage?: boolean }) => Promise<boolean>;
  handleFolderDelete: (id: Identifier, options?: { showMessage?: boolean }) => Promise<boolean>;
  clearDocumentSelection: () => void;
  updateDocumentCaches?: (id: Identifier, updater: (doc: any) => any) => void;
}

const useBulkDocumentActions = ({
  resolveTargetDocumentIds,
  correspondentLookupByName,
  handleCorrespondentCreate,
  setStatusMessage,
  selectedDocumentIds,
  selectedFolderIds,
  handleDocumentsDelete,
  handleFolderDelete,
  clearDocumentSelection,
  updateDocumentCaches,
}: UseBulkDocumentActionsArgs) => {
  const handleBulkCorrespondentAdd = useCallback(
    async ({ name, input, documentIds }: { name?: string; input?: HTMLInputElement | null; documentIds?: Identifier[] }) => {
      const trimmed = name?.trim?.() || '';
      if (!trimmed) {
        setStatusMessage('Correspondent name is required.', 'error');
        return;
      }
      const targets = resolveTargetDocumentIds(documentIds);
      if (!targets.length) {
        setStatusMessage('Select documents before assigning correspondents.', 'error');
        return;
      }

      let target = correspondentLookupByName.get(trimmed.toLowerCase()) || null;
      if (!target) {
        try {
          target = await handleCorrespondentCreate({ name: trimmed });
        } catch {
          return;
        }
      }

      if (!target?.id) {
        setStatusMessage('Unable to resolve correspondent.', 'error');
        return;
      }

      const response: BulkAssignmentResponse = await assignCorrespondentsBulk<BulkAssignmentResponse>({
        document_ids: targets,
        assignments: [
          {
            correspondent_id: target.id,
          },
        ],
        action: 'add',
      });

      const { assigned = 0, removed = 0 } = response;

      if (updateDocumentCaches && target.id) {
        targets.forEach((docId) => {
          updateDocumentCaches(docId, (doc) => {
            if (!doc) return doc;
            const current = Array.isArray((doc as any).correspondents) ? (doc as any).correspondents : [];
            if (current.some((entry: any) => entry?.id === target.id)) {
              return doc;
            }
            return {
              ...(doc as any),
              correspondents: [...current, { id: target.id, name: (target as any).name }],
            };
          });
        });
      }
      const assignedSuffix = assigned === 1 ? '' : 's';
      if (removed > 0) {
        const removedSuffix = removed === 1 ? '' : 's';
        setStatusMessage(
          `Correspondent assigned (${assigned}) and replaced ${removed} link${removedSuffix}.`,
          'success',
        );
      } else {
        setStatusMessage(
          `Correspondent assigned to ${assigned} document${assignedSuffix}.`,
          'success',
        );
      }

      if (input) {
        input.value = '';
      }
    },
    [
      correspondentLookupByName,
      handleCorrespondentCreate,
      resolveTargetDocumentIds,
      setStatusMessage,
      updateDocumentCaches,
    ],
  );

  const handleBulkCorrespondentRemove = useCallback(
    async ({ assignments = [], documentIds }: { assignments?: CorrespondentAssignment[]; documentIds?: Identifier[] }) => {
      if (!assignments.length) {
        setStatusMessage('Select a correspondent to remove.', 'error');
        return;
      }

      const targets = resolveTargetDocumentIds(documentIds);

      if (!targets.length) {
        setStatusMessage('Select documents before removing correspondents.', 'error');
        return;
      }

      const normalizedAssignments = assignments.map((entry) => ({
        correspondent_id: entry.correspondent_id,
      }));

      const response: BulkAssignmentResponse = await assignCorrespondentsBulk<BulkAssignmentResponse>({
        document_ids: targets,
        assignments: normalizedAssignments,
        action: 'remove',
      });

      const { assigned = 0, removed = 0 } = response;
      if (updateDocumentCaches) {
        targets.forEach((docId) => {
          updateDocumentCaches(docId, (doc) => {
            if (!doc || !Array.isArray((doc as any).correspondents)) {
              return doc;
            }
            const filtered = (doc as any).correspondents.filter(
              (entry: any) =>
                entry && !normalizedAssignments.some((assignment) => assignment.correspondent_id === entry.id),
            );
            return filtered.length === (doc as any).correspondents.length
              ? doc
              : { ...(doc as any), correspondents: filtered };
          });
        });
      }

      if (removed > 0) {
        const removedSuffix = removed === 1 ? '' : 's';
        setStatusMessage(
          `Correspondent removed from ${removed} link${removedSuffix}.`,
          'success',
        );
      } else if (assigned > 0) {
        const assignedSuffix = assigned === 1 ? '' : 's';
        setStatusMessage(`Correspondent updated ${assigned} link${assignedSuffix}.`, 'info');
      } else {
        setStatusMessage('No correspondents changed.', 'info');
      }
    },
    [resolveTargetDocumentIds, setStatusMessage, updateDocumentCaches],
  );

  const handleDeleteSelection = useCallback(async () => {
    const docIds = Array.isArray(selectedDocumentIds) ? selectedDocumentIds : [];
    const folderIds = Array.isArray(selectedFolderIds) ? selectedFolderIds : [];

    if (docIds.length === 0 && folderIds.length === 0) {
      return;
    }

    const parts = [];
    if (docIds.length) {
      parts.push(`${docIds.length} document${docIds.length === 1 ? '' : 's'}`);
    }
    if (folderIds.length) {
      parts.push(`${folderIds.length} folder${folderIds.length === 1 ? '' : 's'}`);
    }
    const descriptor = parts.join(' and ');
    const confirmation = parts.length === 1
      ? `Delete ${descriptor}? Folders must be empty before deletion. You can restore documents later from trash.`
      : `Delete ${descriptor}? Folders must be empty before deletion. You can restore documents later from trash.`;

    if (!window.confirm(confirmation)) {
      return;
    }

    let docsOk = true;
    let foldersOk = true;

    if (docIds.length) {
      docsOk = await handleDocumentsDelete(docIds, { showMessage: false });
    }

    if (folderIds.length) {
      for (const folderId of folderIds) {
        const success = await handleFolderDelete(folderId, { showMessage: false });
        if (!success) {
          foldersOk = false;
        }
      }
    }

    if (!docsOk || !foldersOk) {
      setStatusMessage('Some items could not be deleted. Ensure folders are empty before deletion.', 'error');
      return;
    }

    clearDocumentSelection();

    const successParts = [];
    if (docIds.length) {
      successParts.push(docIds.length === 1 ? 'Document deleted.' : 'Documents deleted.');
    }
    if (folderIds.length) {
      successParts.push(folderIds.length === 1 ? 'Folder deleted.' : 'Folders deleted.');
    }

    setStatusMessage(successParts.join(' '), 'success');
  }, [
    clearDocumentSelection,
    handleDocumentsDelete,
    handleFolderDelete,
    selectedDocumentIds,
    selectedFolderIds,
    setStatusMessage,
  ]);

  return {
    handleBulkCorrespondentAdd,
    handleBulkCorrespondentRemove,
    handleDeleteSelection,
  };
};

export default useBulkDocumentActions;
