import { useState, useEffect } from "react";
import { supabase } from "@/integrations/supabase/client";
import { useToast } from "@/hooks/use-toast";
import { Printer, FileDown } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Checkbox } from "@/components/ui/checkbox";
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 { downloadChecksPdf, type CheckData } from "@/utils/checkPdfGenerator";

interface BankAccount {
  id: string;
  account_name: string;
  bank_name: string | null;
  routing_number: string | null;
  account_number: string | null;
  next_check_number: number;
  association_id: string;
}

export default function PrintChecksPage() {
  const { toast } = useToast();
  const [checks, setChecks] = useState<any[]>([]);
  const [bankAccounts, setBankAccounts] = useState<BankAccount[]>([]);
  const [bankAccountId, setBankAccountId] = useState<string>("");
  const [includeMicr, setIncludeMicr] = useState(false);
  const [combinePerVendor, setCombinePerVendor] = useState(true);
  const [loading, setLoading] = useState(true);
  const [printing, setPrinting] = useState(false);
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [vendors, setVendors] = useState<Array<{ name: string; address: string | null; association_id: string | null; association_ids: string[] | null }>>([]);

  const fetchData = async () => {
    setLoading(true);
    const [{ data: checksData }, { data: banksData }, { data: vendorsData }] = await Promise.all([
      supabase
        .from("checks")
        .select("*, associations(name)")
        .in("status", ["draft", "pending"])
        .eq("printed", false)
        .order("created_at"),
      supabase
        .from("bank_accounts")
        .select("id, account_name, bank_name, routing_number, account_number, next_check_number, association_id")
        .eq("status", "active")
        .order("account_name"),
      supabase
        .from("vendors")
        .select("name, address, association_id, association_ids")
        .eq("is_active", true),
    ]);
    setChecks(checksData || []);
    setBankAccounts((banksData || []) as BankAccount[]);
    setVendors((vendorsData || []) as any);
    if (!bankAccountId && banksData && banksData.length > 0) {
      setBankAccountId(banksData[0].id);
    }
    setLoading(false);
  };
  useEffect(() => { fetchData(); }, []);

  const selectedBank = bankAccounts.find((b) => b.id === bankAccountId);

  const toggleSelect = (id: string) => {
    const s = new Set(selected);
    if (s.has(id)) s.delete(id); else s.add(id);
    setSelected(s);
  };
  const selectAll = () => {
    if (selected.size === checks.length) setSelected(new Set());
    else setSelected(new Set(checks.map((c) => c.id)));
  };

  const handlePrint = async () => {
    if (selected.size === 0) {
      toast({ title: "Select checks to print", variant: "destructive" });
      return;
    }
    if (!selectedBank) {
      toast({ title: "Select a bank account", variant: "destructive" });
      return;
    }

    setPrinting(true);
    try {
      const selectedChecks = checks.filter((c) => selected.has(c.id));
      let nextNum = selectedBank.next_check_number;

      // Load layout for this bank's association (optional)
      const { data: layoutRow } = await supabase
        .from("check_layouts")
        .select("*")
        .eq("association_id", selectedBank.association_id)
        .maybeSingle();

      if (includeMicr && (!selectedBank.routing_number || !selectedBank.account_number)) {
        toast({ title: "Missing routing/account number", description: "Add them on the bank account before printing MICR.", variant: "destructive" });
        setPrinting(false);
        return;
      }

      // Fetch bills tied to these checks so we can itemize the stub
      const checkIds = selectedChecks.map((c) => c.id);
      const { data: linkedBills } = await supabase
        .from("bills")
        .select("id, check_id, invoice_number, bill_date, amount, description, vendor_id, vendors(name)")
        .in("check_id", checkIds);
      const billsByCheckId = new Map<string, any[]>();
      for (const b of linkedBills || []) {
        const cid = (b as any).check_id as string;
        if (!billsByCheckId.has(cid)) billsByCheckId.set(cid, []);
        billsByCheckId.get(cid)!.push(b);
      }

      // Group checks by (association_id + normalized payee) when combining is on.
      // Otherwise treat each check as its own group.
      const today = new Date().toISOString().slice(0, 10);
      const groups: Array<{ key: string; checks: any[] }> = [];
      if (combinePerVendor) {
        const map = new Map<string, any[]>();
        for (const c of selectedChecks) {
          const key = `${c.association_id || ""}::${(c.payee || "").trim().toLowerCase()}`;
          if (!map.has(key)) map.set(key, []);
          map.get(key)!.push(c);
        }
        for (const [key, list] of map) groups.push({ key, checks: list });
      } else {
        for (const c of selectedChecks) groups.push({ key: c.id, checks: [c] });
      }

      // Build the printable PDF data + the per-source-check updates
      const printable: CheckData[] = [];
      const sourceUpdates: Array<{ id: string; check_number: string }> = [];
      const txs: any[] = [];

      for (const g of groups) {
        const first = g.checks[0];
        const checkNum = String(nextNum++);
        const total = g.checks.reduce((sum, c) => sum + (Number(c.amount) || 0), 0);

        // Collect line items: prefer linked bills, fall back to the check itself.
        const lineItems: Array<{
          invoice_number?: string | null;
          date?: string | null;
          description?: string | null;
          amount: number;
        }> = [];
        for (const c of g.checks) {
          const billsForCheck = billsByCheckId.get(c.id) || [];
          if (billsForCheck.length > 0) {
            for (const b of billsForCheck) {
              lineItems.push({
                invoice_number: b.invoice_number || null,
                date: b.bill_date || c.check_date || null,
                description: b.description || c.memo || null,
                amount: Number(b.amount) || 0,
              });
            }
          } else {
            // No linked bill — still show this check as a line entry
            lineItems.push({
              invoice_number: c.check_number || null,
              date: c.check_date || null,
              description: c.memo || null,
              amount: Number(c.amount) || 0,
            });
          }
        }

        const memo = g.checks.length > 1
          ? `Combined payment (${lineItems.length} invoice${lineItems.length === 1 ? "" : "s"})`
          : (first.memo || "");

        // Look up vendor address by name (case-insensitive). Prefer a vendor that
        // serves this association if more than one match exists.
        const payeeKey = (first.payee || "").trim().toLowerCase();
        const assocId = first.association_id;
        const matches = vendors.filter(v => (v.name || "").trim().toLowerCase() === payeeKey);
        const vendorMatch =
          matches.find(v =>
            v.association_id === assocId ||
            (Array.isArray(v.association_ids) && v.association_ids.includes(assocId))
          ) || matches[0] || null;
        const payeeAddress = vendorMatch?.address || null;

        printable.push({
          check_number: checkNum,
          check_date: first.check_date || today,
          payee: first.payee,
          payee_address: payeeAddress,
          amount: total,
          memo,
          line_items: lineItems.length > 1 ? lineItems : null,
          bank_account_name: selectedBank.account_name,
          bank_routing_number: selectedBank.routing_number,
          bank_account_number: selectedBank.account_number,
          association_name: first.associations?.name,
          layout: (layoutRow as any) || null,
        });

        // Mark every source check as printed under this combined check number
        for (const c of g.checks) {
          sourceUpdates.push({ id: c.id, check_number: checkNum });
        }

        // One bank transaction per printed check (combined total)
        txs.push({
          association_id: first.association_id,
          bank_account_id: selectedBank.id,
          date: first.check_date || today,
          debit: total,
          credit: 0,
          description: `Check #${checkNum} to ${first.payee}` +
            (g.checks.length > 1 ? ` (combined ${g.checks.length} bills)` : (first.memo ? ` — ${first.memo}` : "")),
          reference_number: checkNum,
          related_entity_id: first.id,
          related_entity_type: "check",
          transaction_type: "check",
        });
      }

      // Generate & download the PDF (one page per group/check)
      await downloadChecksPdf(printable, `checks-${today}.pdf`, { includeMicr });

      // Persist: mark printed, save check numbers + bank account, advance next_check_number
      for (const u of sourceUpdates) {
        await supabase
          .from("checks")
          .update({
            printed: true,
            status: "printed",
            check_number: u.check_number,
            bank_account_id: selectedBank.id,
          })
          .eq("id", u.id);
      }

      if (nextNum > selectedBank.next_check_number) {
        await supabase
          .from("bank_accounts")
          .update({ next_check_number: nextNum })
          .eq("id", selectedBank.id);
      }

      if (txs.length > 0) await supabase.from("bank_transactions").insert(txs);

      toast({
        title: `${printable.length} check(s) printed`,
        description: combinePerVendor && printable.length < selectedChecks.length
          ? `Combined ${selectedChecks.length} items into ${printable.length} vendor check(s).`
          : "PDF downloaded and register updated.",
      });
      setSelected(new Set());
      fetchData();
    } catch (err: any) {
      console.error("Check print failed:", err);
      toast({ title: "Print failed", description: err.message, variant: "destructive" });
    } finally {
      setPrinting(false);
    }
  };

  return (
    <div className="space-y-6">
      <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
        <div>
          <h1 className="text-2xl font-bold text-foreground flex items-center gap-2">
            <Printer className="h-6 w-6 text-primary" /> Print Checks
          </h1>
          <p className="text-sm text-muted-foreground mt-1">Select checks, assign numbers, and generate a printable PDF.</p>
        </div>
        <Button className="gap-2" onClick={handlePrint} disabled={selected.size === 0 || printing || !selectedBank}>
          <FileDown className="h-4 w-4" /> {printing ? "Generating…" : `Print Selected (${selected.size})`}
        </Button>
      </div>

      <Card>
        <CardContent className="pt-6 grid grid-cols-1 sm:grid-cols-2 gap-4">
          <div>
            <Label>Bank Account</Label>
            <Select value={bankAccountId} onValueChange={setBankAccountId}>
              <SelectTrigger><SelectValue placeholder="Select bank account" /></SelectTrigger>
              <SelectContent>
                {bankAccounts.map((b) => (
                  <SelectItem key={b.id} value={b.id}>
                    {b.account_name}{b.bank_name ? ` — ${b.bank_name}` : ""}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div>
            <Label>Next Check #</Label>
            <div className="h-10 px-3 flex items-center rounded-md border bg-muted text-sm font-mono">
              {selectedBank?.next_check_number ?? "—"}
            </div>
          </div>
          <div className="sm:col-span-2 flex items-start gap-3 pt-2 border-t">
            <Checkbox id="micr" checked={includeMicr} onCheckedChange={(v) => setIncludeMicr(!!v)} className="mt-1" />
            <div>
              <Label htmlFor="micr" className="cursor-pointer">Print on blank check stock (include MICR line)</Label>
              <p className="text-xs text-muted-foreground mt-1">
                Enable when printing on blank check paper. Requires routing & account numbers on the bank account, and a MICR-capable printer with magnetic ink for bank acceptance.
              </p>
            </div>
          </div>
          <div className="sm:col-span-2 flex items-start gap-3 pt-2 border-t">
            <Checkbox id="combine" checked={combinePerVendor} onCheckedChange={(v) => setCombinePerVendor(!!v)} className="mt-1" />
            <div>
              <Label htmlFor="combine" className="cursor-pointer">Combine checks per vendor</Label>
              <p className="text-xs text-muted-foreground mt-1">
                Merge selected checks for the same payee (within the same association) into a single check with the totaled amount and a combined memo.
              </p>
            </div>
          </div>

        </CardContent>
      </Card>

      {loading ? (
        <div className="flex justify-center py-12">
          <div className="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent" />
        </div>
      ) : checks.length === 0 ? (
        <Card><CardContent className="py-12 text-center text-muted-foreground">No checks queued for printing.</CardContent></Card>
      ) : (
        <Card>
          <Table>
            <TableHeader>
              <TableRow>
                <TableHead className="w-12">
                  <Checkbox checked={selected.size === checks.length && checks.length > 0} onCheckedChange={selectAll} />
                </TableHead>
                <TableHead>Check #</TableHead>
                <TableHead>Payee</TableHead>
                <TableHead>Amount</TableHead>
                <TableHead>Date</TableHead>
                <TableHead>Status</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {checks.map((c) => (
                <TableRow key={c.id} className={selected.has(c.id) ? "bg-primary/5" : ""}>
                  <TableCell>
                    <Checkbox checked={selected.has(c.id)} onCheckedChange={() => toggleSelect(c.id)} />
                  </TableCell>
                  <TableCell>{c.check_number || <span className="text-muted-foreground italic">auto</span>}</TableCell>
                  <TableCell className="font-medium">{c.payee}</TableCell>
                  <TableCell>${Number(c.amount).toLocaleString()}</TableCell>
                  <TableCell>{c.check_date || "—"}</TableCell>
                  <TableCell><Badge variant="outline" className="capitalize">{c.status}</Badge></TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
        </Card>
      )}
    </div>
  );
}
