import { Dispatch, SetStateAction, useCallback, useState } from 'react';

interface DocumentLike {
  id?: string | number;
  [key: string]: unknown;
}

interface FolderContentsEntry {
  documents?: DocumentLike[];
  [key: string]: unknown;
}

interface UseDocumentsOptions {
  setSearchResults: Dispatch<SetStateAction<DocumentLike[] | null | undefined>>;
  setFolderContents: Dispatch<SetStateAction<Map<string, FolderContentsEntry>>>;
}

const useDocuments = ({ setSearchResults, setFolderContents }: UseDocumentsOptions) => {
  const [documents, setDocuments] = useState<DocumentLike[]>([]);

  const mapDocumentCaches = useCallback(
    (mapper: (doc: DocumentLike) => DocumentLike | undefined) => {
      if (typeof mapper !== 'function') {
        return;
      }

      const applyToList = (list?: DocumentLike[] | null) => {
        let changed = false;
        const safeList = Array.isArray(list) ? list : [];
        const next = safeList.map((doc) => {
          const updated = mapper(doc);
          if (updated === undefined || updated === doc) {
            return doc;
          }
          changed = true;
          return updated;
        });
        return changed ? next : safeList;
      };

      setDocuments((prev) => applyToList(prev));
      setSearchResults((prev) => {
        if (!Array.isArray(prev)) {
          return prev;
        }
        return applyToList(prev);
      });
      setFolderContents((prev) => {
        if (!prev.size) {
          return prev;
        }
        let changed = false;
        const next = new Map();
        prev.forEach((contents, key) => {
          const docs = Array.isArray(contents?.documents) ? contents.documents : null;
          if (!docs || docs.length === 0) {
            next.set(key, contents);
            return;
          }
          let docsChanged = false;
          const updatedDocs = docs.map((doc) => {
            const updated = mapper(doc);
            if (updated === undefined || updated === doc) {
              return doc;
            }
            docsChanged = true;
            return updated;
          });
          if (docsChanged) {
            changed = true;
            next.set(key, { ...contents, documents: updatedDocs });
          } else {
            next.set(key, contents);
          }
        });
        return changed ? next : prev;
      });
    },
    [setFolderContents, setSearchResults],
  );

  const updateDocumentCaches = useCallback(
    (documentId, updater) => {
      if (!documentId || typeof updater !== 'function') {
        return;
      }

      mapDocumentCaches((doc) => {
        if (!doc || doc.id !== documentId) {
          return doc;
        }
        const updated = updater(doc);
        return updated === undefined ? doc : updated;
      });
    },
    [mapDocumentCaches],
  );

  return {
    documents,
    setDocuments,
    mapDocumentCaches,
    updateDocumentCaches,
  };
};

export default useDocuments;
