import { useEffect, useState } from "react";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
import { ArrowRight, FileCheck, Inbox, Loader2, Receipt } from "lucide-react";
import { supabase } from "@/integrations/supabase/client";
import { useNavigate } from "react-router-dom";
import { formatDistanceToNow } from "date-fns";

interface PendingBill {
  id: string;
  source_invoice_id?: string | null;
  invoice_number: string | null;
  amount: number | null;
  due_date: string | null;
  created_at: string;
  associations?: { name: string } | null;
  vendor_name?: string | null;
  source: "bill" | "invoice";
}

interface InboundEmail {
  id: string;
  subject: string | null;
  from_email: string | null;
  status: string;
  created_at: string;
  associations?: { name: string } | null;
}

type PendingBillRow = Omit<PendingBill, "source">;
type PendingBillDbRow = Omit<PendingBill, "source" | "vendor_name"> & {
  notes?: string | null;
  vendors?: { name: string | null } | null;
  invoices?: {
    vendor_name: string | null;
    invoice_number: string | null;
    amount: number | null;
    due_date: string | null;
    created_at: string | null;
  } | null;
};
type BillApprovalStatusRow = { bill_id: string | null; status: string | null };

const fmtMoney = (n: number | null) =>
  typeof n === "number"
    ? n.toLocaleString("en-US", { style: "currency", currency: "USD" })
    : "—";

const getBillDisplayKey = (bill: PendingBill) => {
  if (bill.source === "invoice") return `invoice:${bill.id}`;
  if (bill.source_invoice_id) return `invoice:${bill.source_invoice_id}`;

  const associationName = bill.associations?.name || "";
  const vendorName = bill.vendor_name || "";
  const invoiceNumber = bill.invoice_number || "";
  const amount = typeof bill.amount === "number" ? bill.amount.toFixed(2) : "";

  if (associationName || vendorName || invoiceNumber || amount) {
    return [associationName, vendorName, invoiceNumber, amount].join("|").toLowerCase();
  }

  return `bill:${bill.id}`;
};

const dedupeBillsForDisplay = (items: PendingBill[]) => {
  const seen = new Set<string>();
  return items.filter((bill) => {
    const key = getBillDisplayKey(bill);
    if (seen.has(key)) return false;
    seen.add(key);
    return true;
  });
};

const normalizePendingBill = (bill: PendingBillDbRow): PendingBill => ({
  id: bill.id,
  source_invoice_id: bill.source_invoice_id,
  invoice_number: bill.invoices?.invoice_number ?? bill.invoice_number,
  amount: bill.invoices?.amount ?? bill.amount,
  due_date: bill.invoices?.due_date ?? bill.due_date,
  created_at: bill.created_at,
  associations: bill.associations,
  vendor_name: bill.invoices?.vendor_name ?? bill.vendors?.name ?? bill.notes ?? null,
  source: "bill",
});

export function BillApprovalsCard() {
  const navigate = useNavigate();
  const [tab, setTab] = useState<"approvals" | "inbox">("approvals");
  const [bills, setBills] = useState<PendingBill[]>([]);
  const [pendingCount, setPendingCount] = useState(0);
  const [emails, setEmails] = useState<InboundEmail[]>([]);
  const [inboxCount, setInboxCount] = useState(0);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchAll = async () => {
      setLoading(true);

      // Pending bills (source of truth — what BillApprovalsPage shows)
      const [
        { data: pendingBillsData, count: pendingBillsCount },
        { data: allBillApprovals },
      ] = await Promise.all([
        supabase
          .from("bills")
          .select("id, source_invoice_id, invoice_number, amount, due_date, created_at, notes, associations(name), vendors(name), invoices:source_invoice_id(vendor_name, invoice_number, amount, due_date, created_at)", { count: "exact" })
          .eq("status", "pending")
          .order("created_at", { ascending: false })
          .limit(10),
        // Pull every approval row keyed to a pending bill so we can detect
        // "stuck" bills (status=pending but every approval is already
        // approved/denied). Those should not contribute to the badge.
        supabase
          .from("bill_approvals")
          .select("bill_id, status")
          .not("bill_id", "is", null),
      ]);

      const pendingBillRows = (pendingBillsData || []) as unknown as PendingBillDbRow[];
      const billApprovalStatusRows = (allBillApprovals || []) as BillApprovalStatusRow[];
      const collected: PendingBill[] = pendingBillRows.map(normalizePendingBill);

      // Group approvals by bill_id and figure out which pending bills are
      // truly actionable (have ≥1 pending approval, or none at all).
      const approvalsByBill = new Map<string, string[]>();
      billApprovalStatusRows.forEach((a) => {
        if (!a.bill_id) return;
        const arr = approvalsByBill.get(a.bill_id) || [];
        if (a.status) arr.push(a.status);
        approvalsByBill.set(a.bill_id, arr);
      });
      const stuckBillIds: string[] = [];
      let actionablePendingBills = 0;
      pendingBillRows.forEach((b) => {
        const statuses = approvalsByBill.get(b.id);
        if (!statuses || statuses.length === 0) {
          // No approvers configured — still counts as actionable
          actionablePendingBills += 1;
          return;
        }
        const hasPending = statuses.some((s) => s === "pending");
        if (hasPending) {
          actionablePendingBills += 1;
        } else {
          stuckBillIds.push(b.id);
        }
      });
      // Use the full bills-pending count when only the first 10 were
      // fetched, minus the stuck rows we identified in that page.
      const totalPending = pendingBillsCount || 0;
      const inferredActionable =
        totalPending - (pendingBillsData || []).length + actionablePendingBills;
      setPendingCount(Math.max(0, inferredActionable));

      // Heal stuck pending bills in the background (no await) so the badge
      // matches reality on the next render.
      if (stuckBillIds.length > 0) {
        const healed: { id: string; newStatus: string }[] = [];
        stuckBillIds.forEach((id) => {
          const statuses = approvalsByBill.get(id) || [];
          const newStatus = statuses.some((s) => s === "denied") ? "denied" : "approved";
          healed.push({ id, newStatus });
        });
        const approvedIds = healed.filter((h) => h.newStatus === "approved").map((h) => h.id);
        const deniedIds = healed.filter((h) => h.newStatus === "denied").map((h) => h.id);
        if (approvedIds.length) {
          supabase
            .from("bills")
            .update({ status: "approved", updated_at: new Date().toISOString() })
            .in("id", approvedIds);
        }
        if (deniedIds.length) {
          supabase
            .from("bills")
            .update({ status: "denied", updated_at: new Date().toISOString() })
            .in("id", deniedIds);
        }
      }

      collected.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
      const stuckSet = new Set(stuckBillIds);
      const displayBills = dedupeBillsForDisplay(collected.filter((b) => !stuckSet.has(b.id)));
      setBills(displayBills.slice(0, 5));

      if ((pendingBillsData || []).length < 10) {
        setPendingCount(displayBills.length);
      }

      // Inbound bill emails (inbox)
      const [{ data: inboxData }, { count }] = await Promise.all([
        supabase
          .from("inbound_bill_emails")
          .select("id, subject, from_email, status, created_at, associations(name)")
          .neq("status", "rejected")
          .neq("status", "processed")
          .order("created_at", { ascending: false })
          .limit(5),
        supabase
          .from("inbound_bill_emails")
          .select("*", { count: "exact", head: true })
          .eq("status", "pending"),
      ]);
      setEmails((inboxData || []) as InboundEmail[]);
      setInboxCount(count || 0);

      setLoading(false);
    };

    fetchAll();

    const ch = supabase
      .channel("bill-approvals-card")
      .on("postgres_changes", { event: "*", schema: "public", table: "bills" }, fetchAll)
      .on("postgres_changes", { event: "*", schema: "public", table: "bill_approvals" }, fetchAll)
      .on("postgres_changes", { event: "*", schema: "public", table: "inbound_bill_emails" }, fetchAll)
      .subscribe();

    return () => {
      supabase.removeChannel(ch);
    };
  }, []);

  return (
    <Card className="border shadow-sm h-full flex flex-col">
      <CardHeader className="pb-2 px-4 pt-4">
        <div className="flex items-center justify-between">
          <div>
            <CardTitle className="text-[15px] font-semibold flex items-center gap-2">
              <FileCheck className="h-4 w-4 text-primary" /> Bill Approvals
              {pendingCount + inboxCount > 0 && (
                <Badge variant="destructive" className="text-2xs px-1.5 py-0 h-4 min-w-4 flex items-center justify-center">
                  {pendingCount + inboxCount}
                </Badge>
              )}
            </CardTitle>
            <CardDescription className="text-[12px]">Pending approvals & inbound bills</CardDescription>
          </div>
          <Button
            variant="ghost"
            size="sm"
            className="text-[12px] h-7 gap-1 text-primary"
            onClick={() =>
              navigate(tab === "approvals" ? "/dashboard/bill-approvals-list" : "/dashboard/inbound-bills")
            }
          >
            View all <ArrowRight className="h-3 w-3" />
          </Button>
        </div>
      </CardHeader>
      <CardContent className="px-0 pb-0 flex-1 overflow-hidden">
        <Tabs value={tab} onValueChange={(v) => setTab(v as "approvals" | "inbox")} className="h-full flex flex-col">
          <TabsList className="mx-4 grid w-auto grid-cols-2 h-8">
            <TabsTrigger value="approvals" className="text-xs gap-1.5">
              <Receipt className="h-3 w-3" /> Approvals
              {pendingCount > 0 && (
                <Badge variant="secondary" className="text-2xs px-1 py-0 h-3.5 min-w-3.5">
                  {pendingCount}
                </Badge>
              )}
            </TabsTrigger>
            <TabsTrigger value="inbox" className="text-xs gap-1.5">
              <Inbox className="h-3 w-3" /> Inbox
              {inboxCount > 0 && (
                <Badge variant="secondary" className="text-2xs px-1 py-0 h-3.5 min-w-3.5">
                  {inboxCount}
                </Badge>
              )}
            </TabsTrigger>
          </TabsList>

          <TabsContent value="approvals" className="mt-2 flex-1 overflow-y-auto">
            {loading ? (
              <div className="flex items-center justify-center py-8">
                <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
              </div>
            ) : bills.length === 0 ? (
              <div className="text-center py-8 px-4">
                <Receipt className="h-6 w-6 text-muted-foreground/20 mx-auto mb-2" />
                <p className="text-[13px] text-muted-foreground">No pending approvals</p>
              </div>
            ) : (
              <div className="divide-y divide-border">
                {bills.map((bill) => (
                  <div
                    key={bill.id}
                    className="flex items-center gap-3 px-4 py-2.5 hover:bg-muted/50 transition-colors cursor-pointer"
                    onClick={() =>
                      navigate(
                        bill.source === "invoice"
                          ? "/dashboard/bill-approvals-list"
                          : `/dashboard/bill-approvals/${bill.id}`,
                      )
                    }
                  >
                    <div className="h-7 w-7 rounded-full bg-primary/10 flex items-center justify-center shrink-0">
                      <Receipt className="h-3.5 w-3.5 text-primary" />
                    </div>
                    <div className="min-w-0 flex-1">
                      <p className="text-[13px] font-medium text-foreground truncate">
                        {bill.vendor_name || bill.invoice_number || "Bill"}
                        {bill.invoice_number && bill.vendor_name && (
                          <span className="text-muted-foreground font-normal"> · #{bill.invoice_number}</span>
                        )}
                      </p>
                      <div className="flex items-center gap-2 mt-0.5">
                        <span className="text-2xs font-medium text-foreground">{fmtMoney(bill.amount)}</span>
                        <span className="text-2xs text-muted-foreground truncate">
                          {bill.associations?.name || "—"} ·{" "}
                          {formatDistanceToNow(new Date(bill.created_at), { addSuffix: true })}
                        </span>
                      </div>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </TabsContent>

          <TabsContent value="inbox" className="mt-2 flex-1 overflow-y-auto">
            {loading ? (
              <div className="flex items-center justify-center py-8">
                <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
              </div>
            ) : emails.length === 0 ? (
              <div className="text-center py-8 px-4">
                <Inbox className="h-6 w-6 text-muted-foreground/20 mx-auto mb-2" />
                <p className="text-[13px] text-muted-foreground">Inbox is empty</p>
              </div>
            ) : (
              <div className="divide-y divide-border">
                {emails.map((email) => (
                  <div
                    key={email.id}
                    className="flex items-center gap-3 px-4 py-2.5 hover:bg-muted/50 transition-colors cursor-pointer"
                    onClick={() => navigate("/dashboard/inbound-bills")}
                  >
                    <div className="h-7 w-7 rounded-full bg-primary/10 flex items-center justify-center shrink-0">
                      <Inbox className="h-3.5 w-3.5 text-primary" />
                    </div>
                    <div className="min-w-0 flex-1">
                      <p className="text-[13px] font-medium text-foreground truncate">
                        {email.subject || "(no subject)"}
                      </p>
                      <div className="flex items-center gap-2 mt-0.5">
                        <span className="cc-badge-warning inline-flex items-center rounded-full px-2 py-0.5 text-2xs font-medium border capitalize">
                          {email.status}
                        </span>
                        <span className="text-2xs text-muted-foreground truncate">
                          {email.from_email || "Unknown"} ·{" "}
                          {formatDistanceToNow(new Date(email.created_at), { addSuffix: true })}
                        </span>
                      </div>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </TabsContent>
        </Tabs>
      </CardContent>
    </Card>
  );
}
