import { useCallback } from 'react';

export type Identifier = string | number;

type ApiClient = {
  post: <T = { data: unknown }>(url: string, payload: unknown) => Promise<{ data: T } | T>;
  delete: (url: string) => Promise<unknown>;
};

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

type CorrespondentAssignment = {
  correspondent_id?: Identifier;
};

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

const useBulkDocumentActions = ({
  api,
  resolveTargetDocumentIds,
  correspondentLookupByName,
  handleCorrespondentCreate,
  refreshCurrentFolder,
  setStatusMessage,
  selectedDocumentIds,
  selectedFolderIds,
  handleDocumentsDelete,
  handleFolderDelete,
  clearDocumentSelection,
  setLoading,
}: 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 = await api.post<BulkAssignmentResponse>('/documents/bulk/correspondents', {
        document_ids: targets,
        assignments: [
          {
            correspondent_id: target.id,
          },
        ],
        action: 'add',
      });

      const { assigned = 0, removed = 0 } = 'data' in response ? response.data : response;

      await refreshCurrentFolder();
      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 = '';
      }
    },
    [
      api,
      correspondentLookupByName,
      handleCorrespondentCreate,
      refreshCurrentFolder,
      resolveTargetDocumentIds,
      setStatusMessage,
    ],
  );

  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 = await api.post<BulkAssignmentResponse>('/documents/bulk/correspondents', {
        document_ids: targets,
        assignments: normalizedAssignments,
        action: 'remove',
      });

      const { assigned = 0, removed = 0 } = 'data' in response ? response.data : response;
      await refreshCurrentFolder();

      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');
      }
    },
    [api, refreshCurrentFolder, resolveTargetDocumentIds, setStatusMessage],
  );

  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;
    }

    setLoading(true);
    let docsOk = true;
    let foldersOk = true;

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

      if (folderIds.length) {
        for (const folderId of folderIds) {
          const success = await handleFolderDelete(folderId, { showMessage: false, manageLoading: false });
          if (!success) {
            foldersOk = false;
          }
        }
      }
    } finally {
      setLoading(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,
    setLoading,
    setStatusMessage,
  ]);

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

export default useBulkDocumentActions;
