import { useState } from 'react';

import {
  useAcknowledgePolicy,
  useCreatePolicy,
  useDeletePolicy,
  usePolicies,
  usePolicyAcknowledgments,
  useUpdatePolicy,
} from '@/business/policies/hooks';
import {
  canManagePolicies,
  filterPolicies,
  getPolicyCategoryFilters,
  isPolicyFormValid,
} from '@/business/policies/selectors';
import type { PolicyCategory, PolicyFormInput } from '@/business/policies/types';
import { POLICY_DEFAULT_CATEGORY } from '@/shared/constants/policies';
import type { UserRole } from '@/shared/types/app';

export interface PoliciesPageState {
  readonly canManage: boolean;
  readonly filteredPolicies: NonNullable<ReturnType<typeof usePolicies>['data']>;
  readonly categories: readonly (PolicyCategory | 'all')[];
  readonly searchQuery: string;
  readonly categoryFilter: PolicyCategory | 'all';
  readonly expandedPolicyId: string | null;
  readonly acknowledgedPolicyIds: ReadonlySet<string>;
  readonly showCreateForm: boolean;
  readonly editingPolicyId: string | null;
  readonly createDraft: PolicyFormInput;
  readonly editDraft: PolicyFormInput;
  readonly totalCount: number;
  readonly acknowledgedCount: number;
  readonly isLoading: boolean;
  readonly queryError: unknown;
  readonly mutationError: unknown;
  readonly isMutating: boolean;
  readonly isCreating: boolean;
  readonly isUpdating: boolean;
  readonly isDeleting: boolean;
}

export interface PoliciesPageActions {
  readonly setSearchQuery: (value: string) => void;
  readonly clearSearch: () => void;
  readonly setCategoryFilter: (value: PolicyCategory | 'all') => void;
  readonly setShowCreateForm: (value: boolean) => void;
  readonly updateCreateDraft: (patch: Partial<PolicyFormInput>) => void;
  readonly updateEditDraft: (patch: Partial<PolicyFormInput>) => void;
  readonly submitCreatePolicy: () => Promise<void>;
  readonly startEditingPolicy: (id: string) => void;
  readonly cancelEditingPolicy: () => void;
  readonly submitEditPolicy: (id: string) => Promise<void>;
  readonly deletePolicy: (id: string) => Promise<void>;
  readonly togglePolicyExpanded: (id: string) => void;
  readonly toggleAcknowledgement: (id: string) => void;
}

export interface PoliciesPage {
  readonly state: PoliciesPageState;
  readonly actions: PoliciesPageActions;
}

const emptyPolicyDraft: PolicyFormInput = {
  title: '',
  category: POLICY_DEFAULT_CATEGORY,
  content: '',
};

export function usePoliciesPage(userRole: UserRole): PoliciesPage {
  const canManage = canManagePolicies(userRole);
  const policiesQuery = usePolicies();
  const createPolicy = useCreatePolicy();
  const updatePolicy = useUpdatePolicy();
  const deletePolicyMutation = useDeletePolicy();
  const [searchQuery, setSearchQuery] = useState('');
  const [categoryFilter, setCategoryFilter] = useState<PolicyCategory | 'all'>('all');
  const [expandedPolicyId, setExpandedPolicyId] = useState<string | null>(null);
  const [showCreateForm, setShowCreateForm] = useState(false);
  const [editingPolicyId, setEditingPolicyId] = useState<string | null>(null);
  const [createDraft, setCreateDraft] = useState<PolicyFormInput>(emptyPolicyDraft);
  const [editDraft, setEditDraft] = useState<PolicyFormInput>(emptyPolicyDraft);

  const acknowledgmentsQuery = usePolicyAcknowledgments();
  const acknowledgePolicy = useAcknowledgePolicy();
  const acknowledgedPolicyIds: ReadonlySet<string> = new Set(
    (acknowledgmentsQuery.data ?? []).map((ack) => ack.policyDocumentId),
  );

  const policies = policiesQuery.data ?? [];
  const filteredPolicies = filterPolicies(policies, searchQuery, categoryFilter);
  const isMutating = createPolicy.isPending || updatePolicy.isPending || deletePolicyMutation.isPending;
  const mutationError = createPolicy.error || updatePolicy.error || deletePolicyMutation.error;

  const resetCreateDraft = () => {
    setCreateDraft(emptyPolicyDraft);
  };

  const submitCreatePolicy = async () => {
    if (!isPolicyFormValid(createDraft)) return;

    await createPolicy.mutateAsync(createDraft);
    resetCreateDraft();
    setShowCreateForm(false);
  };

  const startEditingPolicy = (id: string) => {
    const policy = policies.find((item) => item.id === id);
    if (!policy) return;

    setEditDraft({
      title: policy.title,
      category: policy.category,
      content: policy.content,
    });
    setEditingPolicyId(id);
  };

  const submitEditPolicy = async (id: string) => {
    if (!isPolicyFormValid(editDraft)) return;

    await updatePolicy.mutateAsync({ id, policy: editDraft });
    setEditingPolicyId(null);
  };

  const togglePolicyExpanded = (id: string) => {
    setExpandedPolicyId((currentId) => (currentId === id ? null : id));
  };

  // Acknowledgment is a persisted, one-way action (you cannot un-acknowledge a
  // version); re-acknowledging is idempotent on the backend.
  const toggleAcknowledgement = (id: string) => {
    if (!acknowledgedPolicyIds.has(id)) {
      acknowledgePolicy.mutate(id);
    }
  };

  return {
    state: {
      canManage,
      filteredPolicies,
      categories: getPolicyCategoryFilters(),
      searchQuery,
      categoryFilter,
      expandedPolicyId,
      acknowledgedPolicyIds,
      showCreateForm,
      editingPolicyId,
      createDraft,
      editDraft,
      totalCount: policies.length,
      acknowledgedCount: acknowledgedPolicyIds.size,
      isLoading: policiesQuery.isLoading,
      queryError: policiesQuery.error,
      mutationError,
      isMutating,
      isCreating: createPolicy.isPending,
      isUpdating: updatePolicy.isPending,
      isDeleting: deletePolicyMutation.isPending,
    },
    actions: {
      setSearchQuery,
      clearSearch: () => setSearchQuery(''),
      setCategoryFilter,
      setShowCreateForm,
      updateCreateDraft: (patch) => setCreateDraft((currentDraft) => ({ ...currentDraft, ...patch })),
      updateEditDraft: (patch) => setEditDraft((currentDraft) => ({ ...currentDraft, ...patch })),
      submitCreatePolicy,
      startEditingPolicy,
      cancelEditingPolicy: () => setEditingPolicyId(null),
      submitEditPolicy,
      deletePolicy: async (id) => {
        await deletePolicyMutation.mutateAsync(id);
      },
      togglePolicyExpanded,
      toggleAcknowledgement,
    },
  };
}
