import { MutableRefObject, useCallback, useState } from 'react';
import { useStatusToast } from '../../lib/context/StatusToastContext';
import type { TagId, TenantId } from '../../types/identifiers';
import type { Tag } from '../../types/documents';

import { listTags, updateTag, createTag, deleteTag } from '../../lib/api/apiClient';

interface TagManagerInterface {
  buildPayload: (input: { label?: string; color?: string | null }) => { label: string; color: string | null };
}

import useNotifyApiError from '../../hooks/useNotifyApiError';

interface UseTagsOptions {
  // apiClient removed
  tagManager: TagManagerInterface;
  tenantIdRef: MutableRefObject<TenantId | null>;
  setActiveTagFilters: (updater: (prev: Array<TagId>) => Array<TagId>) => void;
  mapDocumentCaches?: (mapper: (doc: any) => any) => void;
}

const useTags = ({
  // apiClient removed
  tagManager,
  tenantIdRef,
  setActiveTagFilters,
  mapDocumentCaches,
}: UseTagsOptions) => {
  const [tags, setTags] = useState<Tag[]>([]);
  const { showToast } = useStatusToast();
  const notifyApiError = useNotifyApiError();

  const refreshTags = useCallback(async () => {
    const requestTenantId = tenantIdRef.current;
    try {
      const data = await listTags();
      if (tenantIdRef.current !== requestTenantId) {
        return;
      }
      setTags(data || []);
    } catch (error) {
      if (tenantIdRef.current !== requestTenantId) {
        return;
      }
      notifyApiError(error, 'Unable to load tags.');
    }
  }, [notifyApiError, tenantIdRef]);

  const handleTagUpdate = useCallback(
    async (tagId: TagId, changes: { label?: string; color?: string | null }) => {
      if (tagId == null) {
        throw new Error('Missing tag identifier.');
      }

      const payload: Record<string, unknown> = {};
      if (changes?.label != null) {
        payload.label = changes.label;
      }
      if (Object.prototype.hasOwnProperty.call(changes, 'color')) {
        payload.color = changes.color;
      }

      if (Object.keys(payload).length === 0) {
        return false;
      }

      try {
        await updateTag(tagId, payload);
        await refreshTags();
        showToast('Tag updated.', 'success');
        return true;
      } catch (error) {
        const message = error.response?.data?.error || 'Failed to update tag.';
        notifyApiError(error, message);
        throw new Error(message);
      }
    },
    [notifyApiError, refreshTags, showToast],
  );

  const handleTagCreate = useCallback(
    async ({ label, color }: { label?: string; color?: string | null } = {}) => {
      const payload = tagManager.buildPayload({ label, color });
      try {
        await createTag(payload);
        await refreshTags();
        showToast('Tag created.', 'success');
      } catch (error) {
        const message = error.response?.data?.error || 'Failed to create tag.';
        notifyApiError(error, message);
        throw new Error(message);
      }
    },
    [notifyApiError, refreshTags, showToast, tagManager],
  );

  const handleTagDelete = useCallback(
    async (tagId: TagId) => {
      if (tagId == null) {
        throw new Error('Missing tag identifier.');
      }

      try {
        await deleteTag(tagId);
        setActiveTagFilters((prev) => prev.filter((id) => id !== tagId));

        const stripTagFromDoc = (doc: any) => {
          if (!doc || !Array.isArray(doc.tags)) {
            return doc;
          }
          const nextTags = doc.tags.filter((tag) => tag.id !== tagId);
          if (nextTags.length === doc.tags.length) {
            return doc;
          }
          return { ...doc, tags: nextTags };
        };

        mapDocumentCaches?.(stripTagFromDoc);

        await refreshTags();
        showToast('Tag deleted.', 'success');
        return true;
      } catch (error) {
        const message = error.response?.data?.error || 'Failed to delete tag.';
        notifyApiError(error, message);
        throw new Error(message);
      }
    },
    [mapDocumentCaches, notifyApiError, refreshTags, setActiveTagFilters, showToast],
  );

  return {
    tags,
    refreshTags,
    handleTagUpdate,
    handleTagCreate,
    handleTagDelete,
    setTags,
  };
};

export default useTags;
