"use client";

import React, { useEffect, useMemo, useState } from "react";
import { useParams, useRouter } from "next/navigation";
import { useAuth } from "@/hooks/useAuth";
import { apiFetch } from "@/lib/api";
import { useDismissingState } from "@/hooks/useDismissingState";
import type { EventCost, EventCostType, EventFinancials, CashupMethod } from "@/types";

const METHOD_LABELS: Record<CashupMethod, string> = { cash: "Cash", card: "Card", eft: "EFT", other: "Other" };
const METHODS: CashupMethod[] = ["cash", "card", "eft", "other"];
const ZAR_DENOMINATIONS = [200, 100, 50, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1];

function money(n: number | null | undefined): string {
  return `R${Number(n || 0).toFixed(2)}`;
}
function denomLabel(v: number): string {
  return v >= 1 ? `R${v}` : `${Math.round(v * 100)}c`;
}

type LineInput = { actualAmount: string; notes: string };

export default function EventCashupPage() {
  const params = useParams<{ id: string }>();
  const eventId = params.id;
  const router = useRouter();
  const { token } = useAuth();

  const [tab, setTab] = useState<"costs" | "reconciliation">("costs");
  const [data, setData] = useState<EventFinancials | null>(null);
  const [eventOptions, setEventOptions] = useState<{ id: string; name: string }[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useDismissingState<string | null>(null);
  const [busy, setBusy] = useState(false);

  const isClosed = data?.event?.cashupStatus === "closed";

  const load = async () => {
    if (!token || !eventId) return;
    setLoading(true);
    setError(null);
    try {
      const [financials, event] = await Promise.all([
        apiFetch<EventFinancials>(`/api/cashups/event/${eventId}`, { authToken: token }),
        apiFetch<any>(`/api/events/${eventId}`, { authToken: token })
      ]);
      setData(financials);
      setEventOptions((event.eventOptions || []).map((o: any) => ({ id: o.id, name: o.name })));
    } catch (e: any) {
      setError(e?.message || "Failed to load cashup data");
    } finally {
      setLoading(false);
    }
  };

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

  return (
    <div className="max-w-4xl mx-auto space-y-4">
      <div className="flex items-center justify-between">
        <div>
          <button className="text-xs text-indigo-600 hover:underline" onClick={() => router.push("/dashboard/admin/cashup")}>← Back to cashup</button>
          <h1 className="text-xl font-semibold mt-1">{data?.event?.title || "Event"} — Cashup</h1>
        </div>
        <span className={"text-xs px-2 py-1 rounded " + (isClosed ? "bg-rose-50 text-rose-700" : "bg-emerald-50 text-emerald-700")}>
          {isClosed ? "Closed" : "Open"}
        </span>
      </div>

      {error && <div className="text-sm text-red-600 bg-red-50 border border-red-100 rounded p-2">{error}</div>}

      <div className="flex gap-2 border-b">
        <button className={"px-3 py-2 text-sm " + (tab === "costs" ? "border-b-2 border-indigo-600 text-indigo-700 font-medium" : "text-gray-500")} onClick={() => setTab("costs")}>Costs</button>
        <button className={"px-3 py-2 text-sm " + (tab === "reconciliation" ? "border-b-2 border-indigo-600 text-indigo-700 font-medium" : "text-gray-500")} onClick={() => setTab("reconciliation")}>Reconciliation</button>
      </div>

      {loading && <div className="text-sm text-gray-400">Loading…</div>}

      {!loading && data && tab === "costs" && (
        <CostsTab eventId={eventId} token={token || ""} costs={data.costs} eventOptions={eventOptions} isClosed={isClosed} onChanged={load} />
      )}

      {!loading && data && tab === "reconciliation" && (
        <ReconciliationTab
          eventId={eventId}
          token={token || ""}
          data={data}
          busy={busy}
          setBusy={setBusy}
          setError={setError}
          onChanged={load}
        />
      )}
    </div>
  );
}

// ─── Costs tab ─────────────────────────────────────────────────────────────

function CostsTab({ eventId, token, costs, eventOptions, isClosed, onChanged }: {
  eventId: string; token: string; costs: EventCost[]; eventOptions: { id: string; name: string }[]; isClosed: boolean; onChanged: () => void;
}) {
  const [editingId, setEditingId] = useState<string | "new" | null>(null);
  const [label, setLabel] = useState("");
  const [costType, setCostType] = useState<EventCostType>("once_off");
  const [amount, setAmount] = useState("");
  const [eventOptionId, setEventOptionId] = useState("");
  const [paidFromMethod, setPaidFromMethod] = useState<"" | CashupMethod>("");
  const [notes, setNotes] = useState("");
  const [saving, setSaving] = useState(false);
  const [err, setErr] = useState<string | null>(null);

  const startNew = () => {
    setEditingId("new");
    setLabel(""); setCostType("once_off"); setAmount(""); setEventOptionId(""); setPaidFromMethod(""); setNotes("");
    setErr(null);
  };

  const startEdit = (c: EventCost) => {
    setEditingId(c.id);
    setLabel(c.label); setCostType(c.costType); setAmount(String(c.amount)); setEventOptionId(c.eventOptionId || ""); setPaidFromMethod(c.paidFromMethod || ""); setNotes(c.notes || "");
    setErr(null);
  };

  const cancel = () => setEditingId(null);

  const save = async () => {
    if (!label.trim()) { setErr("Label is required"); return; }
    if (!amount || isNaN(parseFloat(amount))) { setErr("Amount is required"); return; }
    if (costType === "per_item" && !eventOptionId) { setErr("Select a ticket type for per-item costs"); return; }
    setSaving(true);
    setErr(null);
    try {
      const body = { label: label.trim(), costType, amount: parseFloat(amount), eventOptionId: costType === "per_item" ? eventOptionId : null, paidFromMethod: paidFromMethod || null, notes: notes || null };
      if (editingId === "new") {
        await apiFetch(`/api/events/${eventId}/costs`, { method: "POST", authToken: token, body });
      } else {
        await apiFetch(`/api/costs/${editingId}`, { method: "PUT", authToken: token, body });
      }
      setEditingId(null);
      onChanged();
    } catch (e: any) {
      setErr(e?.message || "Failed to save cost");
    } finally {
      setSaving(false);
    }
  };

  const remove = async (id: string) => {
    if (!confirm("Delete this cost?")) return;
    try {
      await apiFetch(`/api/costs/${id}`, { method: "DELETE", authToken: token });
      onChanged();
    } catch (e: any) {
      alert(e?.message || "Failed to delete cost");
    }
  };

  const totalCosts = costs.reduce((sum, c) => sum + (c.total ?? c.amount), 0);

  return (
    <div className="bg-white border rounded-lg p-4 space-y-3">
      <div className="flex items-center justify-between">
        <div className="text-sm font-medium">Event costs</div>
        {!isClosed && editingId === null && (
          <button className="text-xs px-2 py-1 rounded bg-indigo-600 text-white hover:bg-indigo-700" onClick={startNew}>+ Add cost</button>
        )}
      </div>

      {isClosed && <div className="text-xs text-gray-500">This event is closed — costs can't be changed until it's reopened.</div>}

      <table className="w-full text-sm">
        <thead>
          <tr className="text-left text-gray-500 border-b">
            <th className="py-1">Label</th>
            <th className="py-1">Type</th>
            <th className="py-1">Ticket type</th>
            <th className="py-1">Paid from</th>
            <th className="py-1 text-right">Amount</th>
            <th className="py-1 text-right">Total</th>
            {!isClosed && <th className="py-1"></th>}
          </tr>
        </thead>
        <tbody>
          {costs.map(c => (
            <tr key={c.id} className="border-b last:border-0">
              <td className="py-1.5">{c.label}</td>
              <td className="py-1.5">{c.costType === "once_off" ? "Once-off" : "Per item"}</td>
              <td className="py-1.5">{c.eventOption?.name || "—"}</td>
              <td className="py-1.5 capitalize">{c.paidFromMethod || "—"}</td>
              <td className="py-1.5 text-right">{money(c.amount)}</td>
              <td className="py-1.5 text-right font-medium">{money(c.total ?? c.amount)}</td>
              {!isClosed && (
                <td className="py-1.5 text-right whitespace-nowrap">
                  <button className="text-xs text-indigo-600 hover:underline mr-2" onClick={() => startEdit(c)}>Edit</button>
                  <button className="text-xs text-red-600 hover:underline" onClick={() => remove(c.id)}>Delete</button>
                </td>
              )}
            </tr>
          ))}
          {costs.length === 0 && (
            <tr><td colSpan={7} className="py-3 text-gray-400 text-center">No costs added yet.</td></tr>
          )}
        </tbody>
        {costs.length > 0 && (
          <tfoot>
            <tr>
              <td colSpan={5} className="pt-2 text-right text-gray-500">Total costs</td>
              <td className="pt-2 text-right font-semibold">{money(totalCosts)}</td>
              {!isClosed && <td />}
            </tr>
          </tfoot>
        )}
      </table>

      {editingId !== null && (
        <div className="border rounded p-3 space-y-2 bg-gray-50">
          {err && <div className="text-xs text-red-600">{err}</div>}
          <div className="grid grid-cols-2 gap-2">
            <div>
              <label className="block text-xs text-gray-600 mb-1">Label</label>
              <input className="w-full border rounded px-2 py-1.5 text-sm" value={label} onChange={e => setLabel(e.target.value)} placeholder="e.g. Venue hire" />
            </div>
            <div>
              <label className="block text-xs text-gray-600 mb-1">Type</label>
              <select className="w-full border rounded px-2 py-1.5 text-sm" value={costType} onChange={e => setCostType(e.target.value as EventCostType)}>
                <option value="once_off">Once-off / overall</option>
                <option value="per_item">Per item (ticket type)</option>
              </select>
            </div>
            {costType === "per_item" && (
              <div>
                <label className="block text-xs text-gray-600 mb-1">Ticket type</label>
                <select className="w-full border rounded px-2 py-1.5 text-sm" value={eventOptionId} onChange={e => setEventOptionId(e.target.value)}>
                  <option value="">Select…</option>
                  {eventOptions.map(o => <option key={o.id} value={o.id}>{o.name}</option>)}
                </select>
              </div>
            )}
            <div>
              <label className="block text-xs text-gray-600 mb-1">Amount {costType === "per_item" ? "(per ticket)" : "(flat total)"}</label>
              <input type="number" step="0.01" className="w-full border rounded px-2 py-1.5 text-sm" value={amount} onChange={e => setAmount(e.target.value)} />
            </div>
            <div>
              <label className="block text-xs text-gray-600 mb-1">Paid from (optional)</label>
              <select className="w-full border rounded px-2 py-1.5 text-sm" value={paidFromMethod} onChange={e => setPaidFromMethod(e.target.value as any)}>
                <option value="">Not from event takings</option>
                {METHODS.map(m => <option key={m} value={m}>{METHOD_LABELS[m]}</option>)}
              </select>
              <p className="text-[10px] text-gray-400 mt-0.5">If this was paid out of the door takings (e.g. cash to a vendor), tag it so the Cashup report deducts it from that method's expected amount.</p>
            </div>
            <div className="col-span-2">
              <label className="block text-xs text-gray-600 mb-1">Notes (optional)</label>
              <input className="w-full border rounded px-2 py-1.5 text-sm" value={notes} onChange={e => setNotes(e.target.value)} />
            </div>
          </div>
          <div className="flex gap-2 justify-end">
            <button className="text-xs px-3 py-1.5 rounded border" onClick={cancel} disabled={saving}>Cancel</button>
            <button className="text-xs px-3 py-1.5 rounded bg-indigo-600 text-white hover:bg-indigo-700" onClick={save} disabled={saving}>{saving ? "Saving…" : "Save"}</button>
          </div>
        </div>
      )}
    </div>
  );
}

// ─── Reconciliation tab ─────────────────────────────────────────────────────

function ReconciliationTab({ eventId, token, data, busy, setBusy, setError, onChanged }: {
  eventId: string; token: string; data: EventFinancials; busy: boolean;
  setBusy: (b: boolean) => void; setError: (e: string | null) => void; onChanged: () => void;
}) {
  const isClosed = data.event.cashupStatus === "closed";
  const draftLines = (data.event as any).cashupDraft?.lines as Array<{ method: string; actualAmount?: string | number; notes?: string; denominations?: { value: number; count: number }[] }> | undefined;

  const initialLines: Record<CashupMethod, LineInput> = useMemo(() => {
    const base: Record<CashupMethod, LineInput> = { cash: { actualAmount: "", notes: "" }, card: { actualAmount: "", notes: "" }, eft: { actualAmount: "", notes: "" }, other: { actualAmount: "", notes: "" } };
    for (const l of draftLines || []) {
      if (l.method in base) base[l.method as CashupMethod] = { actualAmount: l.actualAmount != null ? String(l.actualAmount) : "", notes: l.notes || "" };
    }
    return base;
  }, [draftLines]);

  const initialDenomCounts: Record<number, string> = useMemo(() => {
    const cashLine = (draftLines || []).find(l => l.method === "cash");
    const out: Record<number, string> = {};
    for (const d of cashLine?.denominations || []) out[d.value] = String(d.count);
    return out;
  }, [draftLines]);

  const [lines, setLines] = useState<Record<CashupMethod, LineInput>>(initialLines);
  const [denomCounts, setDenomCounts] = useState<Record<number, string>>(initialDenomCounts);
  const [closeNotes, setCloseNotes] = useState("");
  const [reopenNotes, setReopenNotes] = useState("");

  useEffect(() => { setLines(initialLines); setDenomCounts(initialDenomCounts); }, [initialLines, initialDenomCounts]);

  const setLine = (method: CashupMethod, field: keyof LineInput, value: string) => {
    setLines(prev => ({ ...prev, [method]: { ...prev[method], [field]: value } }));
  };

  const cashDenominationsPayload = () => ZAR_DENOMINATIONS
    .map(value => ({ value, count: parseInt(denomCounts[value] || "0", 10) || 0 }))
    .filter(d => d.count > 0);

  const cashActualFromDenoms = cashDenominationsPayload().reduce((sum, d) => sum + d.value * d.count, 0);

  const buildLinesPayload = () => METHODS.map(m => m === "cash"
    ? { method: "cash", denominations: cashDenominationsPayload(), notes: lines.cash.notes || null }
    : { method: m, actualAmount: lines[m].actualAmount === "" ? null : parseFloat(lines[m].actualAmount), notes: lines[m].notes || null });

  const saveDraft = async () => {
    setBusy(true); setError(null);
    try {
      await apiFetch(`/api/cashups/event/${eventId}/draft`, { method: "PUT", authToken: token, body: { lines: buildLinesPayload() } });
      onChanged();
    } catch (e: any) {
      setError(e?.message || "Failed to save draft");
    } finally {
      setBusy(false);
    }
  };

  const closeWithCashup = async () => {
    if (!confirm("Close this event with the entered reconciliation? This will count unallocated donations as profit and fully lock the event until it's reopened.")) return;
    setBusy(true); setError(null);
    try {
      await apiFetch(`/api/cashups/event/${eventId}/close`, { method: "POST", authToken: token, body: { lines: buildLinesPayload(), notes: closeNotes || null } });
      onChanged();
    } catch (e: any) {
      setError(e?.message || "Failed to close event");
    } finally {
      setBusy(false);
    }
  };

  const quickClose = async () => {
    if (!confirm("Quick close this event without a per-method cashup? System totals will be accepted as-is, unallocated donations will be counted as profit, and the event will be fully locked until it's reopened.")) return;
    setBusy(true); setError(null);
    try {
      await apiFetch(`/api/cashups/event/${eventId}/close`, { method: "POST", authToken: token, body: { notes: closeNotes || null } });
      onChanged();
    } catch (e: any) {
      setError(e?.message || "Failed to close event");
    } finally {
      setBusy(false);
    }
  };

  const reopen = async () => {
    if (!confirm("Reopen this event? Registrations, payments, refunds and donations will be allowed again.")) return;
    setBusy(true); setError(null);
    try {
      await apiFetch(`/api/cashups/event/${eventId}/reopen`, { method: "POST", authToken: token, body: { notes: reopenNotes || null } });
      onChanged();
    } catch (e: any) {
      setError(e?.message || "Failed to reopen event");
    } finally {
      setBusy(false);
    }
  };

  const reconciled = data.reconciled;

  return (
    <div className="space-y-4">
      <div className="bg-white border rounded-lg p-4 space-y-3 overflow-auto">
        <div className="text-sm font-medium">Cash-up reconciliation</div>
        <table className="w-full text-sm min-w-[640px]">
          <thead>
            <tr className="text-left text-gray-500 border-b">
              <th className="py-1">Method</th>
              <th className="py-1 text-right">Income</th>
              <th className="py-1 text-right">Costs from method</th>
              <th className="py-1 text-right">Expected cash</th>
              <th className="py-1 text-right">Actual</th>
              <th className="py-1 text-right">Variance</th>
              <th className="py-1">Notes</th>
            </tr>
          </thead>
          <tbody>
            {METHODS.map(m => {
              const r = reconciled?.byMethod?.[m];
              return (
                <tr key={m} className="border-b last:border-0 align-top">
                  <td className="py-1.5">{METHOD_LABELS[m]}</td>
                  <td className="py-1.5 text-right">{money(data.paymentsByMethod[m])}</td>
                  <td className="py-1.5 text-right">{money(data.costsByMethod[m])}</td>
                  <td className="py-1.5 text-right">{money(data.expectedCashByMethod[m])}</td>
                  <td className="py-1.5 text-right">
                    {isClosed ? (
                      money(r?.actual ?? null)
                    ) : m === "cash" ? (
                      money(cashActualFromDenoms)
                    ) : (
                      <input type="number" step="0.01" className="w-28 border rounded px-2 py-1 text-sm text-right" value={lines[m].actualAmount} onChange={e => setLine(m, "actualAmount", e.target.value)} />
                    )}
                  </td>
                  <td className="py-1.5 text-right">
                    {isClosed
                      ? (r?.variance != null ? money(r.variance) : <span className="text-gray-400">not reconciled</span>)
                      : (m === "cash"
                        ? (cashActualFromDenoms > 0 ? money(cashActualFromDenoms - data.expectedCashByMethod[m]) : "—")
                        : (lines[m].actualAmount !== "" ? money(parseFloat(lines[m].actualAmount) - data.expectedCashByMethod[m]) : "—"))}
                  </td>
                  <td className="py-1.5">
                    {isClosed ? (r?.notes || "—") : (
                      <input className="w-full border rounded px-2 py-1 text-sm" value={lines[m].notes} onChange={e => setLine(m, "notes", e.target.value)} />
                    )}
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      <div className="bg-white border rounded-lg p-4 space-y-2">
        <div className="text-sm font-medium">Cash denomination count</div>
        {isClosed ? (
          reconciled?.byMethod?.cash?.denominations?.length ? (
            <table className="text-sm">
              <tbody>
                {reconciled.byMethod.cash.denominations.map(d => (
                  <tr key={d.id}><td className="pr-4 py-0.5">{denomLabel(d.value)}</td><td className="pr-4 py-0.5">× {d.count}</td><td className="py-0.5 text-gray-500">{money(d.value * d.count)}</td></tr>
                ))}
              </tbody>
            </table>
          ) : <div className="text-xs text-gray-400">No denomination breakdown recorded for this cashup.</div>
        ) : (
          <div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
            {ZAR_DENOMINATIONS.map(v => (
              <div key={v} className="flex items-center gap-2">
                <span className="text-sm w-14">{denomLabel(v)}</span>
                <span className="text-xs text-gray-400">×</span>
                <input
                  type="number"
                  min={0}
                  step={1}
                  className="w-16 border rounded px-2 py-1 text-sm"
                  value={denomCounts[v] || ""}
                  onChange={e => setDenomCounts(prev => ({ ...prev, [v]: e.target.value }))}
                />
              </div>
            ))}
          </div>
        )}
      </div>

      <div className="bg-white border rounded-lg p-4 grid grid-cols-1 sm:grid-cols-3 gap-3 text-sm">
        <div>
          <div className="text-gray-500 text-xs">Donations counted as profit</div>
          <div className="font-semibold">{money(data.unallocatedDonationsTotal)}</div>
        </div>
        <div>
          <div className="text-gray-500 text-xs">Total costs</div>
          <div className="font-semibold">{money(data.totalCosts)}</div>
        </div>
        <div>
          <div className="text-gray-500 text-xs">Net profit</div>
          <div className="font-semibold">{money(data.netProfit)}</div>
        </div>
      </div>

      {!isClosed && (
        <div className="bg-white border rounded-lg p-4 space-y-2">
          <label className="block text-xs text-gray-600 mb-1">Notes for closing (optional)</label>
          <input className="w-full border rounded px-2 py-1.5 text-sm" value={closeNotes} onChange={e => setCloseNotes(e.target.value)} />
          <div className="flex flex-wrap gap-2 justify-end pt-1">
            <button className="text-xs px-3 py-1.5 rounded border" disabled={busy} onClick={saveDraft}>Save draft</button>
            <button className="text-xs px-3 py-1.5 rounded bg-amber-600 text-white hover:bg-amber-700" disabled={busy} onClick={quickClose}>Quick close (skip cashup)</button>
            <button className="text-xs px-3 py-1.5 rounded bg-indigo-600 text-white hover:bg-indigo-700" disabled={busy} onClick={closeWithCashup}>Close event with cashup</button>
          </div>
        </div>
      )}

      {isClosed && (
        <div className="bg-white border rounded-lg p-4 space-y-2">
          <label className="block text-xs text-gray-600 mb-1">Notes for reopening (optional)</label>
          <input className="w-full border rounded px-2 py-1.5 text-sm" value={reopenNotes} onChange={e => setReopenNotes(e.target.value)} />
          <div className="flex justify-end">
            <button className="text-xs px-3 py-1.5 rounded bg-rose-600 text-white hover:bg-rose-700" disabled={busy} onClick={reopen}>Reopen event</button>
          </div>
        </div>
      )}

      <div className="bg-white border rounded-lg p-4 space-y-2">
        <div className="text-sm font-medium">History</div>
        {data.history.length === 0 && <div className="text-xs text-gray-400">No close/reopen actions yet.</div>}
        <ul className="space-y-1.5">
          {data.history.map(h => (
            <li key={h.id} className="text-xs border-b last:border-0 pb-1.5 flex items-center justify-between gap-3">
              <span>
                <span className="font-medium">{h.action === "closed" ? "Closed (full cashup)" : h.action === "quick_closed" ? "Quick closed" : "Reopened"}</span>
                {" — "}{h.performedBy?.name || "Unknown"} — {new Date(h.createdAt).toLocaleString()}
              </span>
              {(h.action === "closed" || h.action === "quick_closed") && (
                <span className="text-gray-500 shrink-0">Donations to profit {money(h.unallocatedDonationsTotal)} · Costs {money(h.totalCosts)}</span>
              )}
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}
