import { useMemo, useState, type FormEvent } from "react";
import { useCreateIncome } from "../hooks/useIncome";
import { useDashboard } from "../hooks/useDashboard";
import { Money, Field, Button } from "../components/ui";
import CurrencyInput from "../components/CurrencyInput";
import { previewAllocation } from "../utils/allocatorPreview";
import PercentGuard from "../components/PercentGuard";
import { useToast } from "../components/Toast";
import { useIncomePreview } from "../hooks/useIncomePreview";

function dollarsToCents(input: string): number {
  const n = Number.parseFloat(input || "0");
  if (!Number.isFinite(n)) return 0;
  return Math.round(n * 100);
}

type Alloc = { id: number | string; amountCents: number; name: string };

export default function IncomePage() {
  const [amountStr, setAmountStr] = useState("");
  const { push } = useToast();
  const m = useCreateIncome();
  const dash = useDashboard();

  const cents = dollarsToCents(amountStr);
  const canSubmit = (dash.data?.percentTotal ?? 0) === 100;

  // Server preview (preferred) with client fallback
  const srvPreview = useIncomePreview(cents);
  const preview = useMemo(() => {
    if (!dash.data || cents <= 0) return null;
    if (srvPreview.data) return srvPreview.data;
    // fallback: local simulation
    return previewAllocation(cents, dash.data.fixedPlans, dash.data.variableCategories);
  }, [cents, dash.data, srvPreview.data]);

  const submit = (e: FormEvent) => {
    e.preventDefault();
    if (cents <= 0 || !canSubmit) return;
    m.mutate(
      { amountCents: cents },
      {
        onSuccess: (res) => {
          const fixed = (res.fixedAllocations ?? []).reduce(
            (s: number, a: any) => s + (a.amountCents ?? 0),
            0
          );
          const variable = (res.variableAllocations ?? []).reduce(
            (s: number, a: any) => s + (a.amountCents ?? 0),
            0
          );
          const unalloc = res.remainingUnallocatedCents ?? 0;
          push(
            "ok",
            `Allocated: Fixed ${(fixed / 100).toFixed(2)} + Variable ${(variable / 100).toFixed(
              2
            )}. Unallocated ${(unalloc / 100).toFixed(2)}.`
          );
          setAmountStr("");
        },
        onError: (err: any) => push("err", err?.message ?? "Income failed"),
      }
    );
  };

  const variableAllocations: Alloc[] = useMemo(() => {
    if (!m.data) return [];
    const nameById = new Map<string | number, string>(
      (dash.data?.variableCategories ?? []).map((c) => [c.id as string | number, c.name] as const)
    );
    const grouped = new Map<string | number, number>();
    for (const a of m.data.variableAllocations ?? []) {
      const id = (a as any).variableCategoryId ?? (a as any).id ?? -1;
      grouped.set(id, (grouped.get(id) ?? 0) + (a as any).amountCents);
    }
    return [...grouped.entries()]
      .map(([id, amountCents]) => ({ id, amountCents, name: nameById.get(id) ?? `Category #${id}` }))
      .sort((a, b) => b.amountCents - a.amountCents);
  }, [m.data, dash.data]);

  const fixedAllocations: Alloc[] = useMemo(() => {
    if (!m.data) return [];
    const nameById = new Map<string | number, string>(
      (dash.data?.fixedPlans ?? []).map((p) => [p.id as string | number, p.name] as const)
    );
    const grouped = new Map<string | number, number>();
    for (const a of m.data.fixedAllocations ?? []) {
      const id = (a as any).fixedPlanId ?? (a as any).id ?? -1;
      grouped.set(id, (grouped.get(id) ?? 0) + (a as any).amountCents);
    }
    return [...grouped.entries()]
      .map(([id, amountCents]) => ({ id, amountCents, name: nameById.get(id) ?? `Plan #${id}` }))
      .sort((a, b) => b.amountCents - a.amountCents);
  }, [m.data, dash.data]);

  const hasResult = !!m.data;

  return (
    <div className="stack max-w-lg">
      <PercentGuard />

      <form onSubmit={submit} className="card">
        <h2 className="section-title">Record Income</h2>
        <Field label="Amount (USD)">
          <CurrencyInput value={amountStr} onValue={setAmountStr} />
        </Field>

        <Button disabled={m.isPending || cents <= 0 || !canSubmit}>
          {m.isPending ? "Allocating…" : canSubmit ? "Submit" : "Fix percents to 100%"}
        </Button>

        {/* Live Preview */}
        {!hasResult && preview && (
          <div className="mt-4 stack">
            <div className="row">
              <h3 className="text-sm muted">Preview (not yet applied)</h3>
              <span className="ml-auto text-sm">
                Unallocated: <Money cents={preview.unallocatedCents} />
              </span>
            </div>

            <section className="border border-[--color-ink] rounded-[--radius-xl] p-3 bg-[--color-ink]">
              <div className="row mb-2">
                <h4 className="text-sm muted">Fixed Plans</h4>
                <span className="ml-auto font-semibold">
                  <Money cents={preview.fixed.reduce((s, x) => s + x.amountCents, 0)} />
                </span>
              </div>
              {preview.fixed.length === 0 ? (
                <div className="muted text-sm">No fixed allocations.</div>
              ) : (
                <ul className="list-disc pl-5 space-y-1">
                  {preview.fixed.map((a) => (
                    <li key={a.id} className="row">
                      <span>{a.name}</span>
                      <span className="ml-auto">
                        <Money cents={a.amountCents} />
                      </span>
                    </li>
                  ))}
                </ul>
              )}
            </section>

            <section className="border border-[--color-ink] rounded-[--radius-xl] p-3 bg-[--color-ink]">
              <div className="row mb-2">
                <h4 className="text-sm muted">Variable Categories</h4>
                <span className="ml-auto font-semibold">
                  <Money cents={preview.variable.reduce((s, x) => s + x.amountCents, 0)} />
                </span>
              </div>
              {preview.variable.length === 0 ? (
                <div className="muted text-sm">No variable allocations.</div>
              ) : (
                <ul className="list-disc pl-5 space-y-1">
                  {preview.variable.map((a) => (
                    <li key={a.id} className="row">
                      <span>{a.name}</span>
                      <span className="ml-auto">
                        <Money cents={a.amountCents} />
                      </span>
                    </li>
                  ))}
                </ul>
              )}
            </section>
          </div>
        )}

        {/* Actual Result */}
        {m.error && <div className="toast-err mt-3">⚠️ {(m.error as any).message}</div>}
        {hasResult && (
          <div className="mt-4 stack">
            <div className="row">
              <span className="muted text-sm">Unallocated</span>
              <span className="ml-auto">
                <Money cents={m.data?.remainingUnallocatedCents ?? 0} />
              </span>
            </div>

            <section className="border border-[--color-ink] rounded-[--radius-xl] p-3 bg-[--color-ink]">
              <div className="row mb-2">
                <h3 className="text-sm muted">Fixed Plans (Applied)</h3>
                <span className="ml-auto font-semibold">
                  <Money cents={fixedAllocations.reduce((s, x) => s + x.amountCents, 0)} />
                </span>
              </div>
              <ul className="list-disc pl-5 space-y-1">
                {fixedAllocations.map((a) => (
                  <li key={a.id} className="row">
                    <span>{a.name}</span>
                    <span className="ml-auto">
                      <Money cents={a.amountCents} />
                    </span>
                  </li>
                ))}
              </ul>
            </section>

            <section className="border border-[--color-ink] rounded-[--radius-xl] p-3 bg-[--color-ink]">
              <div className="row mb-2">
                <h3 className="text-sm muted">Variable Categories (Applied)</h3>
                <span className="ml-auto font-semibold">
                  <Money cents={variableAllocations.reduce((s, x) => s + x.amountCents, 0)} />
                </span>
              </div>
              <ul className="list-disc pl-5 space-y-1">
                {variableAllocations.map((a) => (
                  <li key={a.id} className="row">
                    <span>{a.name}</span>
                    <span className="ml-auto">
                      <Money cents={a.amountCents} />
                    </span>
                  </li>
                ))}
              </ul>
            </section>
          </div>
        )}
      </form>
    </div>
  );
}
