import { useState, useCallback } from 'react';
import { updateLedger } from '../api/client';
import type { LedgerData, Person, Expense, Transfer } from '@splint/shared';

/**
 * Ledger state & CRUD operations.
 *
 * Manages the LedgerData state, persists to the server via E2EE API,
 * and returns mutation helpers that each sub-view can use.
 *
 * All monetary amounts are in integer cents — conversion to/from dollars
 * is handled by the modal/form components that call these helpers.
 */
export function useLedger(initialData: LedgerData, ledgerId: string) {
  const [data, setData] = useState<LedgerData>(initialData);
  const [saving, setSaving] = useState(false);

  /** Persist updated data to server and update local state. */
  const save = useCallback(
    async (updated: LedgerData) => {
      const key = localStorage.getItem(`splint-key:${ledgerId}`);
      if (!key) throw new Error('No encryption key found');
      setSaving(true);
      try {
        await updateLedger(ledgerId, key, updated);
        setData(updated);
      } finally {
        setSaving(false);
      }
    },
    [ledgerId],
  );

  // ── People ────────────────────────────────────────────────────────────────

  const addPerson = useCallback(
    async (name: string) => {
      const person: Person = { id: crypto.randomUUID(), name };
      await save({ ...data, people: [...data.people, person] });
    },
    [data, save],
  );

  const removePerson = useCallback(
    async (id: string) => {
      await save({ ...data, people: data.people.filter((p) => p.id !== id) });
    },
    [data, save],
  );

  const updatePerson = useCallback(
    async (id: string, name: string) => {
      await save({
        ...data,
        people: data.people.map((p) => (p.id === id ? { ...p, name } : p)),
      });
    },
    [data, save],
  );

  // ── Expenses ──────────────────────────────────────────────────────────────

  const addExpense = useCallback(
    async (fields: {
      paidBy: string;
      amount: number; // cents
      description: string;
      splitAmong: string[];
    }) => {
      const expense: Expense = {
        ...fields,
        id: crypto.randomUUID(),
        ledgerId,
        createdAt: new Date().toISOString(),
      };
      await save({ ...data, expenses: [...data.expenses, expense] });
    },
    [data, save, ledgerId],
  );

  const updateExpense = useCallback(
    async (
      id: string,
      fields: {
        paidBy: string;
        amount: number; // cents
        description: string;
        splitAmong: string[];
      },
    ) => {
      await save({
        ...data,
        expenses: data.expenses.map((e) =>
          e.id === id ? { ...e, ...fields } : e,
        ),
      });
    },
    [data, save],
  );

  const deleteExpense = useCallback(
    async (id: string) => {
      await save({
        ...data,
        expenses: data.expenses.filter((e) => e.id !== id),
      });
    },
    [data, save],
  );

  // ── Transfers ─────────────────────────────────────────────────────────────

  const addTransfer = useCallback(
    async (fields: {
      from: string;
      to: string;
      amount: number; // cents
    }) => {
      const transfer: Transfer = {
        ...fields,
        id: crypto.randomUUID(),
        ledgerId,
        createdAt: new Date().toISOString(),
      };
      await save({ ...data, transfers: [...data.transfers, transfer] });
    },
    [data, save, ledgerId],
  );

  const updateTransfer = useCallback(
    async (
      id: string,
      fields: { from: string; to: string; amount: number },
    ) => {
      await save({
        ...data,
        transfers: data.transfers.map((t) =>
          t.id === id ? { ...t, ...fields } : t,
        ),
      });
    },
    [data, save],
  );

  const deleteTransfer = useCallback(
    async (id: string) => {
      await save({
        ...data,
        transfers: data.transfers.filter((t) => t.id !== id),
      });
    },
    [data, save],
  );

  // ── Return ────────────────────────────────────────────────────────────────

  return {
    data,
    saving,
    addPerson,
    removePerson,
    updatePerson,
    addExpense,
    updateExpense,
    deleteExpense,
    addTransfer,
    updateTransfer,
    deleteTransfer,
  } as const;
}
