"use client";

import { useEffect, useMemo, useState } from "react";
import { ArrowRightLeft, Banknote, ListChecks, Plus, Trash2, Wallet } from "lucide-react";
import Button from "@/components/ui/Button";
import { calculateAccountBalances, EGRESO_CATEGORIAS, INGRESO_CATEGORIAS, summarizeByCategory } from "@/lib/contabilidad/domain";
import { listCuentas } from "@/lib/pb/cuentas";
import { createMovimiento, deleteMovimiento, listMovimientos, today, updateMovimiento, type MovPayload, type Movimiento, type TipoMov } from "@/lib/pb/movimientos";
import { listProveedores } from "@/lib/pb/proveedores";
import { money } from "@/lib/format";
import type { Cuenta } from "@/lib/types/pago";
import type { Proveedor } from "@/lib/types/proveedor";

type Tab = "movimientos" | "saldos" | "categorias" | "proveedores" | "transferencias";

interface ModalState {
  mode: "add" | "edit";
  tipo: TipoMov;
  id?: string;
  data: {
    fecha: string;
    monto: string;
    cuenta: string;
    cuenta_destino: string;
    categoria: string;
    proveedor: string;
    detalle: string;
    numero_pedido: string;
  };
}

function formatLocalYYYYMMDD(d: Date) {
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, "0");
  const r = String(d.getDate()).padStart(2, "0");
  return `${y}-${m}-${r}`;
}

export default function CajaPage() {
  const [tab, setTab] = useState<Tab>("movimientos");
  const [movements, setMovements] = useState<Movimiento[]>([]);
  const [cuentas, setCuentas] = useState<Cuenta[]>([]);
  const [proveedores, setProveedores] = useState<Proveedor[]>([]);
  const [modal, setModal] = useState<ModalState | null>(null);
  const [loading, setLoading] = useState(true);
  const [err, setErr] = useState("");

  // Filtros
  const [datePreset, setDatePreset] = useState<string>("ultimos_30");
  const [startDate, setStartDate] = useState<string>("");
  const [endDate, setEndDate] = useState<string>("");
  const [selectedMonth, setSelectedMonth] = useState<string>(() => {
    const now = new Date();
    const y = now.getFullYear();
    const m = String(now.getMonth() + 1).padStart(2, "0");
    return `${y}-${m}`;
  });
  const [selectedDate, setSelectedDate] = useState<string>(() => today());
  const [selectedTypes, setSelectedTypes] = useState<TipoMov[]>(["ingreso", "egreso", "transferencia"]);
  const [selectedAccounts, setSelectedAccounts] = useState<string[]>([]);

  async function load() {
    setLoading(true);
    setErr("");
    try {
      const [movs, accounts, providers] = await Promise.all([
        listMovimientos(),
        listCuentas(),
        listProveedores(),
      ]);
      setMovements(movs);
      setCuentas(accounts);
      setProveedores(providers);
      setSelectedAccounts(accounts.map((c) => c.nombre));
    } catch (e) {
      setErr((e as Error).message || "No se pudo cargar Caja");
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    load();
  }, []);

  const dateRange = useMemo(() => {
    const now = new Date();
    const y = now.getFullYear();
    const m = now.getMonth();

    if (datePreset === "ultimos_30") {
      const start = new Date(now);
      start.setDate(start.getDate() - 29);
      return { start: formatLocalYYYYMMDD(start), end: formatLocalYYYYMMDD(now) };
    }
    if (datePreset === "este_mes") {
      const start = new Date(y, m, 1);
      const end = new Date(y, m + 1, 0);
      return {
        start: formatLocalYYYYMMDD(start),
        end: formatLocalYYYYMMDD(end),
      };
    }
    if (datePreset === "mes_pasado") {
      const start = new Date(y, m - 1, 1);
      const end = new Date(y, m, 0);
      return {
        start: formatLocalYYYYMMDD(start),
        end: formatLocalYYYYMMDD(end),
      };
    }
    if (datePreset === "mes") {
      if (!selectedMonth) return { start: null, end: null };
      const [year, month] = selectedMonth.split("-").map(Number);
      const start = new Date(year, month - 1, 1);
      const end = new Date(year, month, 0);
      return {
        start: formatLocalYYYYMMDD(start),
        end: formatLocalYYYYMMDD(end),
      };
    }
    if (datePreset === "dia") {
      if (!selectedDate) return { start: null, end: null };
      return {
        start: selectedDate,
        end: selectedDate,
      };
    }
    if (datePreset === "personalizado") {
      return {
        start: startDate || null,
        end: endDate || null,
      };
    }
    return { start: null, end: null };
  }, [datePreset, startDate, endDate, selectedMonth, selectedDate]);

  const movementsFilteredByDate = useMemo(() => {
    return movements.filter((m) => {
      if (!m.fecha) return true;
      const { start, end } = dateRange;
      if (start && m.fecha < start) return false;
      if (end && m.fecha > end) return false;
      return true;
    });
  }, [movements, dateRange]);

  const movementsForBalances = useMemo(() => {
    const { end } = dateRange;
    if (!end) return movements;
    return movements.filter((m) => !m.fecha || m.fecha <= end);
  }, [movements, dateRange]);

  const movementsFilteredForList = useMemo(() => {
    return movementsFilteredByDate.filter((m) => {
      if (!selectedTypes.includes(m.tipo)) return false;
      if (m.tipo === "transferencia") {
        const sourceMatch = selectedAccounts.includes(m.cuenta);
        const targetMatch = m.cuenta_destino ? selectedAccounts.includes(m.cuenta_destino) : false;
        if (!sourceMatch && !targetMatch) return false;
      } else {
        if (!selectedAccounts.includes(m.cuenta)) return false;
      }
      return true;
    });
  }, [movementsFilteredByDate, selectedTypes, selectedAccounts]);

  const balances = useMemo(() => calculateAccountBalances(
    cuentas.map((cuenta) => ({ nombre: cuenta.nombre, saldo_inicial: cuenta.saldo_inicial || 0 })),
    movementsForBalances,
  ), [cuentas, movementsForBalances]);

  const categorySummary = useMemo(() => summarizeByCategory(movementsFilteredByDate), [movementsFilteredByDate]);
  const ingresos = movementsFilteredByDate.filter((m) => m.tipo === "ingreso").reduce((sum, m) => sum + (m.monto || 0), 0);
  const egresos = movementsFilteredByDate.filter((m) => m.tipo === "egreso").reduce((sum, m) => sum + (m.monto || 0), 0);

  async function save(payload: MovPayload) {
    try {
      const saved = modal?.mode === "edit" && modal.id
        ? await updateMovimiento(modal.id, payload)
        : await createMovimiento(payload);
      setMovements((prev) => [saved, ...prev.filter((item) => item.id !== saved.id)].sort(sortMov));
      setModal(null);
    } catch (e) {
      setErr((e as Error).message || "No se pudo guardar movimiento");
    }
  }

  async function remove(id: string) {
    if (!confirm("¿Borrar movimiento?")) return;
    await deleteMovimiento(id);
    setMovements((prev) => prev.filter((item) => item.id !== id));
  }

  function openAdd(tipo: TipoMov) {
    const cuenta = cuentas[0]?.nombre || "Efectivo";
    setModal({
      mode: "add",
      tipo,
      data: {
        fecha: today(),
        monto: "",
        cuenta,
        cuenta_destino: cuentas.find((c) => c.nombre !== cuenta)?.nombre || cuenta,
        categoria: tipo === "ingreso" ? INGRESO_CATEGORIAS[0] : tipo === "egreso" ? EGRESO_CATEGORIAS[0] : "",
        proveedor: "",
        detalle: "",
        numero_pedido: "",
      },
    });
  }

  function openEdit(m: Movimiento) {
    setModal({
      mode: "edit",
      tipo: m.tipo,
      id: m.id,
      data: {
        fecha: m.fecha || today(),
        monto: String(m.monto || ""),
        cuenta: m.cuenta || cuentas[0]?.nombre || "Efectivo",
        cuenta_destino: m.cuenta_destino || "",
        categoria: m.categoria || "",
        proveedor: m.proveedor || "",
        detalle: m.detalle || "",
        numero_pedido: m.numero_pedido || "",
      },
    });
  }

  return (
    <div className="max-w-6xl space-y-5">
      <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
        <div>
          <h1 className="flex items-center gap-2 text-2xl font-extrabold text-ink">
            <Wallet className="h-6 w-6 text-brand-dark" /> Caja / Contabilidad
          </h1>
          <p className="text-sm text-ink-soft">Orden simple: ingresos, egresos, transferencias, cuentas y proveedores.</p>
        </div>
        <div className="flex flex-wrap gap-2">
          <Button type="button" onClick={() => openAdd("ingreso")}><Plus size={16} /> Ingreso</Button>
          <Button type="button" variant="danger" onClick={() => openAdd("egreso")}><Plus size={16} /> Egreso</Button>
          <Button type="button" variant="secondary" onClick={() => openAdd("transferencia")}><ArrowRightLeft size={16} /> Transferencia</Button>
        </div>
      </div>

      {err && <div className="rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-bad">{err}</div>}

      <div className="grid gap-3 grid-cols-1">
        <Metric label="Neto operativo" value={ingresos - egresos} tone={ingresos - egresos >= 0 ? "good" : "bad"} />
      </div>

      {/* Filtro de Fechas */}
      <div className="card p-4 flex flex-col gap-4 md:flex-row md:items-end justify-between">
        <div className="flex flex-col gap-1.5 flex-1 max-w-xs">
          <span className="text-xs font-bold uppercase text-faint">Filtro de fecha</span>
          <select
            value={datePreset}
            onChange={(e) => setDatePreset(e.target.value)}
            className="field h-10 bg-transparent text-sm"
          >
            <option value="todos">Todos los tiempos</option>
            <option value="ultimos_30">Últimos 30 días</option>
            <option value="dia">Día determinado</option>
            <option value="este_mes">Este mes</option>
            <option value="mes_pasado">Mes pasado</option>
            <option value="mes">Mes determinado</option>
            <option value="personalizado">Rango personalizado</option>
          </select>
        </div>

        {datePreset === "dia" && (
          <div className="flex flex-col gap-1.5 flex-1 max-w-xs">
            <span className="text-xs font-bold uppercase text-faint">Seleccionar día</span>
            <input
              type="date"
              value={selectedDate}
              onChange={(e) => setSelectedDate(e.target.value)}
              className="field h-10 bg-transparent text-sm"
            />
          </div>
        )}

        {datePreset === "mes" && (
          <div className="flex flex-col gap-1.5 flex-1 max-w-xs">
            <span className="text-xs font-bold uppercase text-faint">Seleccionar mes</span>
            <input
              type="month"
              value={selectedMonth}
              onChange={(e) => setSelectedMonth(e.target.value)}
              className="field h-10 bg-transparent text-sm"
            />
          </div>
        )}

        {datePreset === "personalizado" && (
          <div className="flex flex-col sm:flex-row gap-3 flex-1 max-w-lg">
            <div className="flex flex-col gap-1.5 flex-1">
              <span className="text-xs font-bold uppercase text-faint">Desde</span>
              <input
                type="date"
                value={startDate}
                onChange={(e) => setStartDate(e.target.value)}
                className="field h-10 bg-transparent text-sm"
              />
            </div>
            <div className="flex flex-col gap-1.5 flex-1">
              <span className="text-xs font-bold uppercase text-faint">Hasta</span>
              <input
                type="date"
                value={endDate}
                onChange={(e) => setEndDate(e.target.value)}
                className="field h-10 bg-transparent text-sm"
              />
            </div>
          </div>
        )}

        {(datePreset !== "todos" || startDate || endDate || selectedDate !== today() || selectedMonth !== `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, "0")}`) && (
          <Button
            type="button"
            variant="secondary"
            onClick={() => {
              setDatePreset("todos");
              setStartDate("");
              setEndDate("");
              setSelectedDate(today());
              const now = new Date();
              setSelectedMonth(`${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`);
            }}
            className="h-10 px-4"
          >
            Limpiar filtros
          </Button>
        )}
      </div>

      <div className="flex gap-2 overflow-x-auto rounded-xl border border-line bg-surface p-1">
        {[
          ["movimientos", "Movimientos"],
          ["saldos", "Saldos"],
          ["categorias", "Categorías"],
          ["proveedores", "Proveedores"],
          ["transferencias", "Transferencias"],
        ].map(([value, label]) => (
          <button
            key={value}
            type="button"
            onClick={() => setTab(value as Tab)}
            className={`shrink-0 rounded-lg px-3 py-2 text-sm font-semibold ${tab === value ? "bg-brand-soft text-brand-dark" : "text-faint hover:text-ink"}`}
          >
            {label}
          </button>
        ))}
      </div>

      {loading ? (
        <div className="py-16 text-center text-sm text-faint">Cargando...</div>
      ) : tab === "saldos" ? (
        <section className="grid gap-3 md:grid-cols-3">
          {Object.entries(balances).map(([name, balance]) => <Metric key={name} label={name} value={balance} tone={balance >= 0 ? "good" : "bad"} />)}
        </section>
      ) : tab === "categorias" ? (
        <SummaryList items={Object.entries(categorySummary).map(([label, value]) => ({ label, value }))} />
      ) : tab === "proveedores" ? (
        <SummaryList items={providerTotals(movementsFilteredByDate).map(([label, value]) => ({ label, value: -value }))} />
      ) : tab === "transferencias" ? (
        <MovementList movements={movementsFilteredByDate.filter((m) => m.tipo === "transferencia")} onEdit={openEdit} onDelete={remove} />
      ) : (
        <div className="grid gap-5 md:grid-cols-[240px_1fr]">
          {/* Sidebar de Filtros de Movimientos */}
          <aside className="card p-4 space-y-5 h-fit">
            <div className="space-y-2">
              <h3 className="text-xs font-bold uppercase text-faint tracking-wider">Tipo de Movimiento</h3>
              <div className="flex flex-col gap-2">
                {[
                  { v: "ingreso", l: "Ingresos" },
                  { v: "egreso", l: "Egresos" },
                  { v: "transferencia", l: "Transferencias" }
                ].map(({ v, l }) => (
                  <label key={v} className="flex items-center gap-2 text-sm font-medium text-ink-soft cursor-pointer hover:text-ink">
                    <input
                      type="checkbox"
                      checked={selectedTypes.includes(v as TipoMov)}
                      onChange={(e) => {
                        const checked = e.target.checked;
                        setSelectedTypes((prev) =>
                          checked ? [...prev, v as TipoMov] : prev.filter((x) => x !== v)
                        );
                      }}
                      className="rounded text-brand focus:ring-brand"
                    />
                    {l}
                  </label>
                ))}
              </div>
            </div>

            <div className="space-y-2">
              <div className="flex items-center justify-between">
                <h3 className="text-xs font-bold uppercase text-faint tracking-wider">Cuentas</h3>
                <button
                  type="button"
                  onClick={() => {
                    const allSelected = selectedAccounts.length === cuentas.length;
                    setSelectedAccounts(allSelected ? [] : cuentas.map((c) => c.nombre));
                  }}
                  className="text-[10px] font-bold text-brand hover:underline"
                >
                  {selectedAccounts.length === cuentas.length ? "Ninguna" : "Todas"}
                </button>
              </div>
              <div className="flex flex-col gap-2 max-h-60 overflow-y-auto pr-1">
                {cuentas.map((c) => (
                  <label key={c.id} className="flex items-center gap-2 text-sm font-medium text-ink-soft cursor-pointer hover:text-ink">
                    <input
                      type="checkbox"
                      checked={selectedAccounts.includes(c.nombre)}
                      onChange={(e) => {
                        const checked = e.target.checked;
                        setSelectedAccounts((prev) =>
                          checked ? [...prev, c.nombre] : prev.filter((x) => x !== c.nombre)
                        );
                      }}
                      className="rounded text-brand focus:ring-brand"
                    />
                    {c.nombre}
                  </label>
                ))}
              </div>
            </div>
          </aside>

          {/* Lista de Movimientos */}
          <div className="space-y-3">
            <MovementList movements={movementsFilteredForList} onEdit={openEdit} onDelete={remove} />
          </div>
        </div>
      )}

      {modal && (
        <MovimientoModal
          modal={modal}
          cuentas={cuentas.map((cuenta) => cuenta.nombre)}
          proveedores={proveedores}
          onClose={() => setModal(null)}
          onSave={save}
        />
      )}
    </div>
  );
}

function Metric({ label, value, tone }: { label: string; value: number; tone: "good" | "bad" }) {
  return (
    <div className="rounded-xl border border-line bg-surface p-4">
      <div className="text-xs font-bold uppercase text-faint">{label}</div>
      <div className={`mt-1 text-xl font-extrabold tabular-nums ${tone === "good" ? "text-good" : "text-bad"}`}>{money(value)}</div>
    </div>
  );
}

function MovementList({ movements, onEdit, onDelete }: { movements: Movimiento[]; onEdit: (m: Movimiento) => void; onDelete: (id: string) => void }) {
  if (!movements.length) return <div className="card p-10 text-center text-sm text-faint">Sin movimientos.</div>;
  return (
    <section className="overflow-hidden rounded-xl border border-line bg-surface">
      <div className="divide-y divide-line">
        {movements.map((m) => (
          <article key={m.id} className="grid gap-3 px-4 py-3 md:grid-cols-[110px_120px_1fr_130px_72px] md:items-center">
            <span className="text-sm font-bold text-faint">{m.fecha}</span>
            <span className={`rounded-full px-2 py-1 text-xs font-extrabold ${m.tipo === "ingreso" ? "bg-green-100 text-green-800" : m.tipo === "egreso" ? "bg-red-100 text-red-800" : "bg-blue-100 text-blue-800"}`}>
              {m.tipo}
            </span>
            <div className="min-w-0">
              <div className="truncate text-sm font-bold text-ink">
                {m.tipo === "transferencia" ? `${m.cuenta} -> ${m.cuenta_destino || "-"}` : `${m.cuenta} · ${m.categoria || "Otros"}`}
              </div>
              <div className="flex flex-wrap items-center gap-2 mt-0.5">
                <span className="truncate text-xs text-faint">{m.expand?.proveedor?.nombre || m.detalle || m.notas || ""}</span>
                {m.numero_pedido && (
                  <span className="inline-flex items-center rounded bg-brand-soft px-1.5 py-0.5 text-[10px] font-bold text-brand-dark">
                    Pedido {m.numero_pedido}
                  </span>
                )}
              </div>
            </div>
            <span className={`text-sm font-extrabold tabular-nums ${m.tipo === "egreso" ? "text-bad" : "text-good"}`}>
              {m.tipo === "egreso" ? "-" : ""}{money(m.monto)}
            </span>
            <div className="flex gap-1">
              <button type="button" onClick={() => onEdit(m)} className="rounded-lg border border-line px-2 py-1 text-xs font-semibold text-ink-soft hover:text-ink">Editar</button>
              <button type="button" onClick={() => onDelete(m.id)} className="rounded-lg border border-line px-2 py-1 text-bad"><Trash2 size={13} /></button>
            </div>
          </article>
        ))}
      </div>
    </section>
  );
}

function SummaryList({ items }: { items: Array<{ label: string; value: number }> }) {
  if (!items.length) return <div className="card p-10 text-center text-sm text-faint">Sin datos.</div>;
  return (
    <section className="grid gap-2">
      {items.sort((a, b) => Math.abs(b.value) - Math.abs(a.value)).map((item) => (
        <div key={item.label} className="flex items-center justify-between rounded-xl border border-line bg-surface px-4 py-3">
          <span className="font-semibold text-ink">{item.label}</span>
          <span className={`font-extrabold tabular-nums ${item.value >= 0 ? "text-good" : "text-bad"}`}>{money(item.value)}</span>
        </div>
      ))}
    </section>
  );
}

function MovimientoModal({ modal, cuentas, proveedores, onClose, onSave }: {
  modal: ModalState;
  cuentas: string[];
  proveedores: Proveedor[];
  onClose: () => void;
  onSave: (payload: MovPayload) => Promise<void>;
}) {
  const [data, setData] = useState(modal.data);
  const [saving, setSaving] = useState(false);
  const isTransfer = modal.tipo === "transferencia";
  const categories = modal.tipo === "ingreso" ? INGRESO_CATEGORIAS : EGRESO_CATEGORIAS;

  async function submit(e: React.FormEvent) {
    e.preventDefault();
    setSaving(true);
    await onSave({
      tipo: modal.tipo,
      monto: Number(data.monto) || 0,
      cuenta: data.cuenta,
      cuenta_destino: isTransfer ? data.cuenta_destino : "",
      categoria: isTransfer ? "" : data.categoria,
      proveedor: modal.tipo === "egreso" ? data.proveedor || undefined : undefined,
      detalle: data.detalle,
      numero_pedido: modal.tipo === "ingreso" ? data.numero_pedido : "",
      fecha: data.fecha,
    });
    setSaving(false);
  }

  return (
    <div className="fixed inset-0 z-50 grid place-items-center bg-black/50 p-4" onClick={onClose}>
      <form onSubmit={submit} className="card w-full max-w-lg space-y-3 p-5 shadow-[var(--shadow-lg)]" onClick={(e) => e.stopPropagation()}>
        <h2 className="flex items-center gap-2 text-lg font-extrabold text-ink">
          {isTransfer ? <ArrowRightLeft size={18} /> : <Banknote size={18} />} {modal.mode === "add" ? "Nuevo" : "Editar"} {modal.tipo}
        </h2>
        <Field label="Fecha"><input type="date" value={data.fecha} onChange={(e) => setData({ ...data, fecha: e.target.value })} className="field" required /></Field>
        <Field label="Monto"><input type="number" value={data.monto} onChange={(e) => setData({ ...data, monto: e.target.value })} className="field" required /></Field>
        <Field label={isTransfer ? "Cuenta origen" : "Cuenta"}><Select value={data.cuenta} onChange={(value) => setData({ ...data, cuenta: value })} options={cuentas} /></Field>
        {isTransfer ? (
          <Field label="Cuenta destino"><Select value={data.cuenta_destino} onChange={(value) => setData({ ...data, cuenta_destino: value })} options={cuentas} /></Field>
        ) : (
          <Field label="Categoría"><Select value={data.categoria} onChange={(value) => setData({ ...data, categoria: value })} options={[...categories]} /></Field>
        )}
        {modal.tipo === "egreso" && (
          <Field label="Proveedor"><Select value={data.proveedor} onChange={(value) => setData({ ...data, proveedor: value })} options={["", ...proveedores.map((p) => p.id)]} labels={{ "": "Sin proveedor", ...Object.fromEntries(proveedores.map((p) => [p.id, p.nombre])) }} /></Field>
        )}
        {modal.tipo === "ingreso" && (
          <Field label="Pedido"><input value={data.numero_pedido} onChange={(e) => setData({ ...data, numero_pedido: e.target.value })} className="field" placeholder="Opcional" /></Field>
        )}
        <Field label="Detalle"><input value={data.detalle} onChange={(e) => setData({ ...data, detalle: e.target.value })} className="field" placeholder="Opcional" /></Field>
        <div className="flex justify-end gap-2 pt-2">
          <Button type="button" variant="secondary" onClick={onClose}>Cancelar</Button>
          <Button type="submit" loading={saving}>Guardar</Button>
        </div>
      </form>
    </div>
  );
}

function Field({ label, children }: { label: string; children: React.ReactNode }) {
  return <label className="grid gap-1.5 text-sm font-semibold text-ink-soft">{label}{children}</label>;
}

function Select({ value, onChange, options, labels = {} }: { value: string; onChange: (value: string) => void; options: readonly string[]; labels?: Record<string, string> }) {
  return (
    <select value={value} onChange={(e) => onChange(e.target.value)} className="field">
      {options.map((option) => <option key={option} value={option}>{labels[option] || option}</option>)}
    </select>
  );
}

function providerTotals(movements: Movimiento[]): Array<[string, number]> {
  const totals = new Map<string, number>();
  for (const movement of movements) {
    if (movement.tipo !== "egreso" || !movement.expand?.proveedor?.nombre) continue;
    totals.set(movement.expand.proveedor.nombre, (totals.get(movement.expand.proveedor.nombre) || 0) + movement.monto);
  }
  return [...totals.entries()];
}

function sortMov(a: Movimiento, b: Movimiento) {
  return (b.fecha || "").localeCompare(a.fecha || "") || (b.created || "").localeCompare(a.created || "");
}
