import { useMemo, useState } from "react";
import { useMutation, useQuery } from "@tanstack/react-query";
import { AlertTriangle, Check, Plus, Scale, Trash2, Wallet } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { AccountSelect } from "@/components/AccountSelect";
import { EmptyState, SectionCard, StatCard } from "@/components/ui-kit";
import { formatDate, formatMoney, todayISO } from "@/lib/format";
import { listAccounts, recordOwnerInvestment } from "@/lib/erp";


export type InvestorOwner = {
  id: string;
  name: string;
  ownership_percentage: number;
  is_active: boolean;
  capital_account_id: string | null;
};

type Line = { key: string; owner_id: string; amount: string };

const newLine = (): Line => ({ key: crypto.randomUUID(), owner_id: "", amount: "" });

/** Splits a capital raise across owners, shows each stake as a percentage and posts it to capital. */
export function InvestorCalculator({
  owners,
  onDone,
}: {
  owners: InvestorOwner[];
  onDone: () => void;
}) {
  const [total, setTotal] = useState("");
  const [date, setDate] = useState(todayISO());
  const [accountId, setAccountId] = useState<string | null>(null);
  const [notes, setNotes] = useState("");
  const [lines, setLines] = useState<Line[]>([newLine(), newLine()]);

  const totalTarget = Number(total) || 0;
  const entered = lines.reduce((s, l) => s + (Number(l.amount) || 0), 0);
  const basis = totalTarget > 0 ? totalTarget : entered;
  const difference = totalTarget > 0 ? totalTarget - entered : 0;
  const balanced = Math.abs(difference) < 0.005;

  const ownerById = useMemo(() => new Map(owners.map((o) => [o.id, o])), [owners]);

  const { data: accounts = [] } = useQuery({
    queryKey: ["accounts"],
    queryFn: async () =>
      (await listAccounts()) as unknown as { id: string; code: string; name: string }[],
  });
  const accountLabel = (id: string | null | undefined) => {
    if (!id) return null;
    const a = accounts.find((x) => x.id === id);
    return a ? `${a.code} · ${a.name}` : null;
  };

  /** Exact double-entry lines the posting engine will write, one pair per stake. */
  const journalLines = useMemo(() => {
    const depositLabel = accountLabel(accountId);
    return lines
      .map((l) => ({ owner: ownerById.get(l.owner_id), amount: Number(l.amount) || 0 }))
      .filter((l) => l.owner && l.amount > 0)
      .flatMap(({ owner, amount }) => {
        const capitalLabel = accountLabel(owner!.capital_account_id);
        return [
          {
            key: `${owner!.id}-d`,
            account: depositLabel ?? "Select a deposit account",
            missing: !depositLabel,
            memo: `Investment received — ${owner!.name}`,
            debit: amount,
            credit: 0,
          },
          {
            key: `${owner!.id}-c`,
            account: capitalLabel ?? `No capital account linked for ${owner!.name}`,
            missing: !capitalLabel,
            memo: `Owner capital — ${owner!.name}`,
            debit: 0,
            credit: amount,
          },
        ];
      });
  }, [lines, accountId, accounts, ownerById]);

  const previewDebit = journalLines.reduce((s, l) => s + l.debit, 0);
  const previewCredit = journalLines.reduce((s, l) => s + l.credit, 0);
  const previewIssues = journalLines.some((l) => l.missing);

  const setLine = (key: string, patch: Partial<Line>) =>
    setLines((prev) => prev.map((l) => (l.key === key ? { ...l, ...patch } : l)));


  const splitByOwnership = () => {
    const active = owners.filter((o) => o.is_active && Number(o.ownership_percentage ?? 0) > 0);
    if (totalTarget <= 0) {
      toast.error("Enter the total investment amount first");
      return;
    }
    if (active.length === 0) {
      toast.error("No active owners with an ownership percentage");
      return;
    }
    const sum = active.reduce((s, o) => s + Number(o.ownership_percentage ?? 0), 0);
    setLines(
      active.map((o) => ({
        key: crypto.randomUUID(),
        owner_id: o.id,
        amount: ((totalTarget * Number(o.ownership_percentage ?? 0)) / sum).toFixed(2),
      })),
    );
  };

  const splitEvenly = () => {
    const filled = lines.filter((l) => l.owner_id);
    if (totalTarget <= 0 || filled.length === 0) {
      toast.error("Enter a total amount and pick owners first");
      return;
    }
    const each = totalTarget / filled.length;
    setLines((prev) => prev.map((l) => (l.owner_id ? { ...l, amount: each.toFixed(2) } : l)));
  };

  const post = useMutation({
    mutationFn: async () => {
      if (!accountId) throw new Error("Choose the cash or bank account receiving the funds");
      const payload = lines
        .map((l) => ({ owner: ownerById.get(l.owner_id), amount: Number(l.amount) || 0 }))
        .filter((l) => l.owner && l.amount > 0);
      if (payload.length === 0) throw new Error("Add at least one owner with an amount");
      const dupes = new Set(payload.map((p) => p.owner!.id));
      if (dupes.size !== payload.length) throw new Error("Each owner may only appear once");
      const unlinked = payload.filter((p) => !p.owner!.capital_account_id);
      if (unlinked.length > 0) {
        throw new Error(
          `Link a capital account for: ${unlinked.map((p) => p.owner!.name).join(", ")}`,
        );
      }
      if (totalTarget > 0 && !balanced) throw new Error("Allocated amounts must match the total investment");
      for (const p of payload) {
        await recordOwnerInvestment({
          owner_id: p.owner!.id,
          date,
          amount: p.amount,
          deposit_account_id: accountId,
          notes:
            notes ||
            `Investment ${((p.amount / (basis || 1)) * 100).toFixed(2)}% of ${formatMoney(basis)}`,
        });
      }
      return payload.length;
    },
    onSuccess: (count) => {
      toast.success(`${count} investment${count > 1 ? "s" : ""} posted to owner capital`);
      setLines([newLine(), newLine()]);
      setTotal("");
      setNotes("");
      onDone();
    },
    onError: (e: Error) => toast.error(e.message),
  });

  return (
    <div className="space-y-6">
      <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
        <StatCard label="Total investment" value={formatMoney(totalTarget)} tone="accent" />
        <StatCard label="Allocated" value={formatMoney(entered)} />
        <StatCard
          label="Unallocated"
          value={formatMoney(difference)}
          hint={totalTarget > 0 ? (balanced ? "Fully allocated" : "Adjust the amounts") : "Enter a total"}
          tone={totalTarget > 0 ? (balanced ? "positive" : "negative") : undefined}
        />
        <StatCard label="Investors" value={String(lines.filter((l) => l.owner_id && Number(l.amount) > 0).length)} />
      </div>

      <SectionCard title="Investment round">
        <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
          <div className="space-y-2">
            <Label htmlFor="inv-total">Total amount</Label>
            <Input
              id="inv-total"
              type="number"
              step="0.01"
              min="0"
              placeholder="0.00"
              value={total}
              onChange={(e) => setTotal(e.target.value)}
            />
          </div>
          <div className="space-y-2">
            <Label htmlFor="inv-date">Date</Label>
            <Input id="inv-date" type="date" value={date} onChange={(e) => setDate(e.target.value)} />
          </div>
          <div className="space-y-2">
            <Label>Deposit into</Label>
            <AccountSelect value={accountId} onChange={setAccountId} typeCodes={["CASH"]} />
          </div>
          <div className="space-y-2">
            <Label htmlFor="inv-notes">Notes</Label>
            <Input
              id="inv-notes"
              placeholder="Optional memo"
              value={notes}
              onChange={(e) => setNotes(e.target.value)}
            />
          </div>
        </div>
        <div className="mt-4 flex flex-wrap gap-2">
          <Button type="button" variant="outline" size="sm" onClick={splitByOwnership}>
            <Scale className="mr-2 size-4" />
            Split by ownership %
          </Button>
          <Button type="button" variant="outline" size="sm" onClick={splitEvenly}>
            <Wallet className="mr-2 size-4" />
            Split evenly
          </Button>
        </div>
      </SectionCard>

      <SectionCard title="Investor allocation" flush>
        <Table>
          <TableHeader>
            <TableRow>
              <TableHead className="w-[28%]">Owner</TableHead>
              <TableHead className="w-[20%]">Investment</TableHead>
              <TableHead>Share of investment</TableHead>
              <TableHead className="w-[18%]">Capital account</TableHead>
              <TableHead className="w-10" />
            </TableRow>
          </TableHeader>
          <TableBody>
            {lines.map((l) => {
              const amount = Number(l.amount) || 0;
              const pct = basis > 0 ? (amount / basis) * 100 : 0;
              const owner = ownerById.get(l.owner_id);
              return (
                <TableRow key={l.key}>
                  <TableCell>
                    <Select value={l.owner_id} onValueChange={(v) => setLine(l.key, { owner_id: v })}>
                      <SelectTrigger>
                        <SelectValue placeholder="Select owner" />
                      </SelectTrigger>
                      <SelectContent>
                        {owners.map((o) => (
                          <SelectItem key={o.id} value={o.id}>
                            {o.name}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </TableCell>
                  <TableCell>
                    <Input
                      type="number"
                      step="0.01"
                      min="0"
                      placeholder="0.00"
                      value={l.amount}
                      onChange={(e) => setLine(l.key, { amount: e.target.value })}
                    />
                  </TableCell>
                  <TableCell>
                    <div className="flex items-center gap-3">
                      <div className="h-2 w-full max-w-[220px] overflow-hidden rounded-full bg-muted">
                        <div
                          className="h-full rounded-full bg-primary transition-all"
                          style={{ width: `${Math.min(100, Math.max(0, pct))}%` }}
                        />
                      </div>
                      <span className="tabular-nums text-sm font-medium">{pct.toFixed(2)}%</span>
                    </div>
                  </TableCell>
                  <TableCell className="text-xs text-muted-foreground">
                    {owner
                      ? owner.capital_account_id
                        ? "Linked"
                        : "Not linked"
                      : "—"}
                  </TableCell>
                  <TableCell>
                    <Button
                      type="button"
                      variant="ghost"
                      size="icon"
                      aria-label="Remove investor row"
                      onClick={() => setLines((prev) => (prev.length > 1 ? prev.filter((p) => p.key !== l.key) : prev))}
                    >
                      <Trash2 className="size-4" />
                    </Button>
                  </TableCell>
                </TableRow>
              );
            })}
          </TableBody>
        </Table>
        <div className="flex flex-wrap items-center justify-between gap-3 border-t p-4">
          <Button type="button" variant="outline" size="sm" onClick={() => setLines((p) => [...p, newLine()])}>
            <Plus className="mr-2 size-4" />
            Add investor
          </Button>
          <div className="flex flex-wrap items-center gap-4">
            {totalTarget > 0 && (
              <span
                className={`flex items-center gap-2 text-sm ${balanced ? "text-muted-foreground" : "text-destructive"}`}
              >
                {balanced ? <Check className="size-4" /> : <AlertTriangle className="size-4" />}
                {balanced
                  ? `Allocated ${formatMoney(entered)} of ${formatMoney(totalTarget)}`
                  : `${formatMoney(Math.abs(difference))} ${difference > 0 ? "unallocated" : "over-allocated"}`}
              </span>
            )}
            <Button type="button" onClick={() => post.mutate()} disabled={post.isPending}>
              Post to owner capital
            </Button>
          </div>
        </div>
      </SectionCard>

      <SectionCard
        title={`Journal preview — ${formatDate(date)}`}
        flush
        actions={
          journalLines.length > 0 ? (
            <span
              className={`flex items-center gap-2 text-xs ${previewIssues ? "text-destructive" : "text-muted-foreground"}`}
            >
              {previewIssues ? <AlertTriangle className="size-3.5" /> : <Check className="size-3.5" />}
              {previewIssues
                ? "Resolve the highlighted accounts before posting"
                : `Balanced · ${journalLines.length} lines`}
            </span>
          ) : undefined
        }
      >
        {journalLines.length === 0 ? (
          <div className="p-4">
            <EmptyState
              title="Nothing to post yet"
              description="Pick investors, amounts and a deposit account to see the exact General Ledger lines."
            />
          </div>
        ) : (
          <div className="overflow-x-auto">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead className="w-[38%]">Account</TableHead>
                  <TableHead>Memo</TableHead>
                  <TableHead className="text-right">Debit</TableHead>
                  <TableHead className="text-right">Credit</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {journalLines.map((l) => (
                  <TableRow key={l.key}>
                    <TableCell className={l.missing ? "text-destructive" : "font-medium"}>
                      {l.account}
                    </TableCell>
                    <TableCell className="text-muted-foreground">{l.memo}</TableCell>
                    <TableCell className="num text-right">
                      {l.debit > 0 ? formatMoney(l.debit) : "—"}
                    </TableCell>
                    <TableCell className="num text-right">
                      {l.credit > 0 ? formatMoney(l.credit) : "—"}
                    </TableCell>
                  </TableRow>
                ))}
                <TableRow className="font-semibold">
                  <TableCell colSpan={2}>Total</TableCell>
                  <TableCell className="num text-right">{formatMoney(previewDebit)}</TableCell>
                  <TableCell className="num text-right">{formatMoney(previewCredit)}</TableCell>
                </TableRow>
              </TableBody>
            </Table>
          </div>
        )}
      </SectionCard>
    </div>
  );
}
