import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import {
  createPolicyDocument,
  deletePolicyDocument,
  listPolicyDocuments,
  updatePolicyDocument,
} from '@/shared/api/policyDocuments';
import { POLICY_DOCUMENT_PAGE_CATEGORY, POLICY_QUERY_KEYS } from '@/shared/constants/policies';
import { SAFETY_PROTOCOL_DEFAULT_TAG } from '@/shared/constants/safetyProtocols';
import { mapApiListRows } from '@/shared/business/apiListRows';
import { useInvalidatingMutation } from '@/shared/business/queryMutations';
import { useAcknowledgePolicy, usePolicyAcknowledgments } from '@/business/policies/hooks';
import {
  toSafetyProtocolMutationDto,
  toSafetyProtocolViewModel,
} from '@/business/safety-protocols/mappers';
import {
  canManageSafetyProtocols,
  isSafetyDraftValid,
} from '@/business/safety-protocols/selectors';
import type {
  SafetyProtocolDraft,
  SafetyProtocolListKey,
  SafetyProtocolViewModel,
} from '@/business/safety-protocols/types';
import type { UserRole } from '@/shared/types/app';

const EMPTY_SAFETY_PROTOCOLS: readonly SafetyProtocolViewModel[] = [];

/** Safety protocols = `policy_documents` of category `safety_protocol`. */
export function useSafetyProtocols() {
  return useQuery({
    queryKey: POLICY_QUERY_KEYS.safetyDocuments,
    queryFn: () =>
      mapApiListRows(
        listPolicyDocuments(POLICY_DOCUMENT_PAGE_CATEGORY.safetyProtocols),
        toSafetyProtocolViewModel,
      ),
  });
}

// Acknowledgment is shared across all policy documents (handbook + safety):
export {
  usePolicyAcknowledgments as useSafetyAcknowledgments,
  useAcknowledgePolicy as useAcknowledgeSafetyProtocol,
} from '@/business/policies/hooks';

function createEmptySafetyDraft(): SafetyProtocolDraft {
  return {
    title: '',
    tag: SAFETY_PROTOCOL_DEFAULT_TAG,
    steps: [''],
    autismConsiderations: [''],
  };
}

interface SafetyUpdateInput {
  readonly id: string;
  readonly draft: SafetyProtocolDraft;
}

/**
 * Page workflow for the Safety Protocols module — mirrors the F.R.A.M.E. module
 * hook: list + persistent acknowledgment plus a manager-gated authoring flow
 * (create / inline edit / delete) over the unified `policy_documents` store. The
 * `steps` and `autismConsiderations` drafts are dynamic: rows can be added and
 * removed independently so each protocol carries its own count.
 */
export function useSafetyProtocolsModule(userRole: UserRole) {
  const canManage = canManageSafetyProtocols(userRole);
  const protocolsQuery = useSafetyProtocols();
  const acknowledgmentsQuery = usePolicyAcknowledgments();
  const acknowledgeProtocol = useAcknowledgePolicy();

  const [expandedId, setExpandedId] = useState<string | null>(null);
  const [showNewForm, setShowNewForm] = useState(false);
  const [editId, setEditId] = useState<string | null>(null);
  const [draft, setDraft] = useState<SafetyProtocolDraft>(createEmptySafetyDraft);
  const [formError, setFormError] = useState<string | null>(null);

  function resetForm() {
    setShowNewForm(false);
    setEditId(null);
    setDraft(createEmptySafetyDraft());
    setFormError(null);
  }

  const createMutation = useInvalidatingMutation({
    mutationFn: (input: SafetyProtocolDraft) =>
      createPolicyDocument(toSafetyProtocolMutationDto(input)),
    invalidateQueryKey: POLICY_QUERY_KEYS.safetyDocuments,
    onSuccess: resetForm,
  });

  const updateMutation = useInvalidatingMutation({
    mutationFn: (input: SafetyUpdateInput) =>
      updatePolicyDocument(input.id, toSafetyProtocolMutationDto(input.draft)),
    invalidateQueryKey: POLICY_QUERY_KEYS.safetyDocuments,
    onSuccess: resetForm,
  });

  const deleteMutation = useInvalidatingMutation({
    mutationFn: (id: string) => deletePolicyDocument(id),
    invalidateQueryKey: POLICY_QUERY_KEYS.safetyDocuments,
    onSuccess: resetForm,
  });

  const protocols = protocolsQuery.data ?? EMPTY_SAFETY_PROTOCOLS;
  const acknowledgedIds: ReadonlySet<string> = new Set(
    (acknowledgmentsQuery.data ?? []).map((ack) => ack.policyDocumentId),
  );

  function updateDraftField(patch: Partial<SafetyProtocolDraft>) {
    setDraft((current) => ({ ...current, ...patch }));
  }

  function updateListItem(key: SafetyProtocolListKey, index: number, value: string) {
    setDraft((current) => {
      const next = [...current[key]];
      next[index] = value;
      return { ...current, [key]: next };
    });
  }

  function addListItem(key: SafetyProtocolListKey) {
    setDraft((current) => ({ ...current, [key]: [...current[key], ''] }));
  }

  function removeListItem(key: SafetyProtocolListKey, index: number) {
    setDraft((current) => {
      const next = current[key].filter((_, itemIndex) => itemIndex !== index);
      // Keep at least one editable row so the field never disappears entirely.
      return { ...current, [key]: next.length > 0 ? next : [''] };
    });
  }

  function openNewForm() {
    setEditId(null);
    setDraft(createEmptySafetyDraft());
    setFormError(null);
    setShowNewForm(true);
  }

  function startEditing(protocol: SafetyProtocolViewModel) {
    setShowNewForm(false);
    setEditId(protocol.id);
    setFormError(null);
    setDraft({
      title: protocol.title,
      tag: protocol.tag ?? SAFETY_PROTOCOL_DEFAULT_TAG,
      steps: protocol.steps.length > 0 ? [...protocol.steps] : [''],
      autismConsiderations:
        protocol.autismConsiderations.length > 0
          ? [...protocol.autismConsiderations]
          : [''],
    });
  }

  async function saveDraft() {
    if (!isSafetyDraftValid(draft)) {
      setFormError('Add a title and at least one procedure step before saving.');
      return;
    }

    if (editId) {
      await updateMutation.mutateAsync({ id: editId, draft });
    } else {
      await createMutation.mutateAsync(draft);
    }
  }

  async function deleteProtocol(id: string) {
    await deleteMutation.mutateAsync(id);
  }

  // Acknowledgment is a persisted, one-way action; re-acknowledging is idempotent.
  function acknowledge(id: string) {
    if (!acknowledgedIds.has(id)) {
      acknowledgeProtocol.mutate(id);
    }
  }

  function toggleExpanded(id: string) {
    setExpandedId((current) => (current === id ? null : id));
  }

  return {
    canManage,
    protocols,
    acknowledgedIds,
    expandedId,
    showNewForm,
    editId,
    draft,
    formError,
    isLoading: protocolsQuery.isLoading,
    error: protocolsQuery.error,
    isSaving: createMutation.isPending || updateMutation.isPending,
    isDeleting: deleteMutation.isPending,
    openNewForm,
    startEditing,
    cancelForm: resetForm,
    updateDraftField,
    updateListItem,
    addListItem,
    removeListItem,
    saveDraft,
    deleteProtocol,
    acknowledge,
    toggleExpanded,
  };
}
