import { useState, useEffect, useMemo } from "react";
import { supabase } from "@/integrations/supabase/client";
import { useToast } from "@/hooks/use-toast";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Badge } from "@/components/ui/badge";
import { Checkbox } from "@/components/ui/checkbox";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog";
import { Loader2, FileText, Search, Trash2, DollarSign, Receipt } from "lucide-react";
import { format } from "date-fns";
import { generateInvoicePdf } from "@/lib/generateInvoicePdf";

type Expense = {
  id: string;
  association_id: string;
  date: string;
  description: string | null;
  amount: number;
  category: string | null;
  billable_type: string | null;
  status: string;
  is_credit: boolean;
  quantity: number | null;
  unit_price: number | null;
  vendor_name: string | null;
  address: string | null;
};

type Association = { id: string; name: string; address: string | null; city: string | null; state: string | null; zip: string | null; email: string | null; phone: string | null; website: string | null };

type EditableItem = {
  id: string;
  include: boolean;
  date: string;
  description: string;
  category: string;
  address: string;
  vendor: string;
  quantity: number;
  unit_price: number;
  amount: number;
  is_credit: boolean;
  receipt_url?: string;
};

const fmtCurrency = (v: number) => new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(v);

export default function InvoiceClientsPage() {
  const { toast } = useToast();
  const [loading, setLoading] = useState(true);
  const [expenses, setExpenses] = useState<Expense[]>([]);
  const [associations, setAssociations] = useState<Association[]>([]);
  const [search, setSearch] = useState("");

  // Review dialog
  const [reviewOpen, setReviewOpen] = useState(false);
  const [reviewClient, setReviewClient] = useState<Association | null>(null);
  const [reviewItems, setReviewItems] = useState<EditableItem[]>([]);
  const [generating, setGenerating] = useState(false);

  useEffect(() => { fetchData(); }, []);

  const fetchData = async () => {
    setLoading(true);
    const [expRes, assocRes] = await Promise.all([
      supabase.from("billable_expenses").select("*").eq("status", "pending").order("date", { ascending: false }),
      supabase.from("associations").select("id,name,address,city,state,zip,email,phone,website").eq("status", "active").order("name"),
    ]);
    if (expRes.data) setExpenses(expRes.data as Expense[]);
    if (assocRes.data) setAssociations(assocRes.data as Association[]);
    setLoading(false);
  };

  // Aggregate per client
  const clientRows = useMemo(() => {
    const map = new Map<string, { client: Association; charges: number; credits: number; net: number; count: number }>();
    associations.forEach(a => map.set(a.id, { client: a, charges: 0, credits: 0, net: 0, count: 0 }));
    expenses.forEach(e => {
      const row = map.get(e.association_id);
      if (!row) return;
      const amt = Number(e.amount) || 0;
      const isCredit = e.is_credit || amt < 0;
      if (isCredit) row.credits += Math.abs(amt);
      else row.charges += Math.abs(amt);
      row.net = row.charges - row.credits;
      row.count += 1;
    });
    return Array.from(map.values())
      .filter(r => r.count > 0)
      .filter(r => !search || r.client.name.toLowerCase().includes(search.toLowerCase()))
      .sort((a, b) => b.net - a.net);
  }, [expenses, associations, search]);

  const totalUnbilled = useMemo(() => clientRows.reduce((s, r) => s + r.net, 0), [clientRows]);

  const openReview = (client: Association) => {
    const items: EditableItem[] = expenses
      .filter(e => e.association_id === client.id)
      .map(e => ({
        id: e.id,
        include: true,
        date: e.date,
        description: e.description || e.category || "Billable Expense",
        category: e.category || "",
        address: e.address || "",
        vendor: e.vendor_name || "",
        quantity: Number(e.quantity || 1),
        unit_price: e.unit_price ? Number(e.unit_price) : Math.abs(Number(e.amount)),
        amount: Number(e.amount),
        is_credit: e.is_credit || Number(e.amount) < 0,
        receipt_url: (e as any).receipt_url || undefined,
      }));
    setReviewClient(client);
    setReviewItems(items);
    setReviewOpen(true);
  };

  const updateItem = (idx: number, patch: Partial<EditableItem>) => {
    setReviewItems(prev => {
      const next = [...prev];
      next[idx] = { ...next[idx], ...patch };
      // Recalc amount when qty/unit_price changes
      if (patch.quantity !== undefined || patch.unit_price !== undefined) {
        const item = next[idx];
        const calc = item.quantity * item.unit_price;
        next[idx].amount = item.is_credit ? -Math.abs(calc) : Math.abs(calc);
      }
      if (patch.is_credit !== undefined) {
        next[idx].amount = patch.is_credit ? -Math.abs(next[idx].amount) : Math.abs(next[idx].amount);
      }
      return next;
    });
  };

  const removeItem = (idx: number) => {
    setReviewItems(prev => prev.filter((_, i) => i !== idx));
  };

  const reviewTotals = useMemo(() => {
    const included = reviewItems.filter(i => i.include);
    const charges = included.filter(i => !i.is_credit).reduce((s, i) => s + Math.abs(i.amount), 0);
    const credits = included.filter(i => i.is_credit).reduce((s, i) => s + Math.abs(i.amount), 0);
    return { charges, credits, net: charges - credits, count: included.length };
  }, [reviewItems]);

  const handleGenerate = async () => {
    if (!reviewClient) return;
    const included = reviewItems.filter(i => i.include);
    if (!included.length) {
      toast({ variant: "destructive", title: "No items selected" });
      return;
    }
    setGenerating(true);
    try {
      const invoiceNumber = `INV-${Date.now().toString(36).toUpperCase()}`;
      const issueDate = new Date().toISOString().split("T")[0];
      const dueDate = new Date(Date.now() + 30 * 86400000).toISOString().split("T")[0];

      // Persist any line-item edits back to billable_expenses
      await Promise.all(included.map(i =>
        supabase.from("billable_expenses").update({
          description: i.description || null,
          category: i.category || null,
          address: i.address || null,
          vendor_name: i.vendor || null,
          quantity: i.quantity,
          unit_price: i.unit_price,
          amount: i.amount,
          is_credit: i.is_credit,
        }).eq("id", i.id)
      ));

      // Create invoice record
      const { data: invData, error: invError } = await supabase.from("client_invoices").insert({
        invoice_number: invoiceNumber,
        association_id: reviewClient.id,
        amount: reviewTotals.charges,
        credits: reviewTotals.credits,
        total: reviewTotals.net,
        status: "sent",
        issue_date: issueDate,
        due_date: dueDate,
        source: "billable_expenses",
        created_by: (await supabase.auth.getUser()).data.user?.id,
      }).select().single();

      if (invError) throw invError;

      if (invData) {
        await supabase.from("client_invoice_items").insert(
          included.map(i => ({
            invoice_id: invData.id,
            billable_expense_id: i.id,
            description: i.description,
            category: i.category,
            date: i.date || null,
            quantity: i.quantity,
            unit_price: i.unit_price,
            amount: i.amount,
            is_credit: i.is_credit,
          }))
        );
      }

      // Fetch company settings
      const { data: settings } = await supabase.from("company_settings").select("key, value");
      const getSetting = (key: string) => settings?.find((s: any) => s.key === key)?.value || "";

      await generateInvoicePdf({
        invoiceNumber,
        invoiceDate: issueDate,
        dueDate,
        clientName: reviewClient.name,
        clientAddress: reviewClient.address || "",
        clientCity: reviewClient.city || "",
        clientState: reviewClient.state || "",
        clientZip: reviewClient.zip || "",
        items: included.map(i => ({
          date: i.date ? format(new Date(i.date + "T12:00:00"), "MM/dd/yyyy") : "",
          description: i.description,
          category: i.category,
          quantity: i.quantity,
          unitPrice: i.unit_price,
          amount: i.amount,
          isCredit: i.is_credit,
          address: i.address || undefined,
          vendor: i.vendor || undefined,
          receiptUrl: i.receipt_url || undefined,
        })),
        companyName: getSetting("company_name") || "Avria Community Management, LLC",
        companyAddress: getSetting("company_address") || "",
        companyEmail: getSetting("company_email") || reviewClient.email || "",
        companyPhone: getSetting("company_phone") || reviewClient.phone || "",
        companyWebsite: getSetting("company_website") || reviewClient.website || "",
        logoUrl: getSetting("company_logo") || "",
      });

      // Mark expenses as invoiced
      await supabase.from("billable_expenses").update({ status: "invoiced" }).in("id", included.map(i => i.id));

      toast({ title: "Invoice generated", description: `${reviewClient.name} — ${fmtCurrency(reviewTotals.net)}` });
      setReviewOpen(false);
      setReviewClient(null);
      setReviewItems([]);
      fetchData();
    } catch (err: any) {
      console.error(err);
      toast({ variant: "destructive", title: "Failed to generate invoice", description: err.message });
    } finally {
      setGenerating(false);
    }
  };

  if (loading) {
    return <div className="flex items-center justify-center h-[50vh]"><Loader2 className="h-8 w-8 animate-spin text-muted-foreground" /></div>;
  }

  return (
    <div className="max-w-7xl mx-auto space-y-6">
      {/* Summary */}
      <Card className="bg-gradient-to-br from-emerald-500 to-teal-600 text-white border-none">
        <CardContent className="p-6">
          <div className="flex items-start justify-between">
            <div>
              <p className="text-sm font-medium opacity-90">Total Unbilled</p>
              <p className="text-4xl font-bold mt-1">{fmtCurrency(totalUnbilled)}</p>
              <p className="text-sm opacity-80 mt-2">{clientRows.length} client{clientRows.length === 1 ? "" : "s"} with pending charges</p>
            </div>
            <div className="bg-white/20 rounded-full p-3">
              <DollarSign className="h-6 w-6" />
            </div>
          </div>
        </CardContent>
      </Card>

      {/* Header */}
      <div className="flex items-center justify-between gap-4">
        <div>
          <h2 className="text-xl font-bold">Invoice Clients</h2>
          <p className="text-sm text-muted-foreground">Review unbilled expenses and generate invoices per client</p>
        </div>
        <div className="relative w-72">
          <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
          <Input value={search} onChange={e => setSearch(e.target.value)} placeholder="Search clients..." className="pl-9" />
        </div>
      </div>

      {/* Client table */}
      <Card>
        <CardContent className="p-0">
          {clientRows.length === 0 ? (
            <div className="p-12 text-center text-muted-foreground">
              <Receipt className="h-12 w-12 mx-auto mb-3 opacity-40" />
              <p>No clients with unbilled expenses.</p>
            </div>
          ) : (
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead>Client</TableHead>
                  <TableHead className="text-right">Items</TableHead>
                  <TableHead className="text-right">Charges</TableHead>
                  <TableHead className="text-right">Credits</TableHead>
                  <TableHead className="text-right">Unbilled Total</TableHead>
                  <TableHead className="text-right">Action</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {clientRows.map(row => (
                  <TableRow key={row.client.id}>
                    <TableCell className="font-medium">{row.client.name}</TableCell>
                    <TableCell className="text-right">
                      <Badge variant="secondary">{row.count}</Badge>
                    </TableCell>
                    <TableCell className="text-right">{fmtCurrency(row.charges)}</TableCell>
                    <TableCell className="text-right text-destructive">
                      {row.credits > 0 ? `-${fmtCurrency(row.credits)}` : fmtCurrency(0)}
                    </TableCell>
                    <TableCell className="text-right font-semibold">{fmtCurrency(row.net)}</TableCell>
                    <TableCell className="text-right">
                      <Button size="sm" onClick={() => openReview(row.client)} className="gap-1.5">
                        <FileText className="h-4 w-4" /> Invoice Now
                      </Button>
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          )}
        </CardContent>
      </Card>

      {/* Review Dialog */}
      <Dialog open={reviewOpen} onOpenChange={setReviewOpen}>
        <DialogContent className="max-w-6xl max-h-[90vh] overflow-y-auto">
          <DialogHeader>
            <DialogTitle>Review Invoice — {reviewClient?.name}</DialogTitle>
            <DialogDescription>
              Edit, remove, or exclude line items before generating the invoice. Edits are saved back to the originating billable expense.
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-4">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead className="w-10"></TableHead>
                  <TableHead className="w-32">Date</TableHead>
                  <TableHead>Description</TableHead>
                  <TableHead className="w-32">Category</TableHead>
                  <TableHead className="w-40">Address</TableHead>
                  <TableHead className="w-20 text-right">Qty</TableHead>
                  <TableHead className="w-24 text-right">Unit Price</TableHead>
                  <TableHead className="w-24 text-right">Amount</TableHead>
                  <TableHead className="w-16">Credit</TableHead>
                  <TableHead className="w-10"></TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {reviewItems.map((item, idx) => (
                  <TableRow key={item.id} className={!item.include ? "opacity-40" : ""}>
                    <TableCell>
                      <Checkbox checked={item.include} onCheckedChange={(c) => updateItem(idx, { include: !!c })} />
                    </TableCell>
                    <TableCell>
                      <Input type="date" value={item.date} onChange={e => updateItem(idx, { date: e.target.value })} className="h-8" />
                    </TableCell>
                    <TableCell>
                      <Input value={item.description} onChange={e => updateItem(idx, { description: e.target.value })} className="h-8" />
                    </TableCell>
                    <TableCell>
                      <Input value={item.category} onChange={e => updateItem(idx, { category: e.target.value })} className="h-8" />
                    </TableCell>
                    <TableCell>
                      <Input value={item.address} onChange={e => updateItem(idx, { address: e.target.value })} className="h-8" />
                    </TableCell>
                    <TableCell>
                      <Input type="number" step="0.01" value={item.quantity} onChange={e => updateItem(idx, { quantity: parseFloat(e.target.value) || 0 })} className="h-8 text-right" />
                    </TableCell>
                    <TableCell>
                      <Input type="number" step="0.01" value={item.unit_price} onChange={e => updateItem(idx, { unit_price: parseFloat(e.target.value) || 0 })} className="h-8 text-right" />
                    </TableCell>
                    <TableCell className="text-right font-medium">{fmtCurrency(item.amount)}</TableCell>
                    <TableCell>
                      <Checkbox checked={item.is_credit} onCheckedChange={(c) => updateItem(idx, { is_credit: !!c })} />
                    </TableCell>
                    <TableCell>
                      <Button variant="ghost" size="icon" className="h-8 w-8" onClick={() => removeItem(idx)}>
                        <Trash2 className="h-4 w-4 text-destructive" />
                      </Button>
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>

            {/* Totals */}
            <div className="flex justify-end">
              <div className="w-64 space-y-1.5 text-sm">
                <div className="flex justify-between"><span className="text-muted-foreground">Items</span><span>{reviewTotals.count}</span></div>
                <div className="flex justify-between"><span className="text-muted-foreground">Charges</span><span>{fmtCurrency(reviewTotals.charges)}</span></div>
                <div className="flex justify-between"><span className="text-muted-foreground">Credits</span><span className="text-destructive">-{fmtCurrency(reviewTotals.credits)}</span></div>
                <div className="flex justify-between border-t pt-1.5 font-semibold text-base"><span>Total</span><span>{fmtCurrency(reviewTotals.net)}</span></div>
              </div>
            </div>
          </div>

          <DialogFooter>
            <Button variant="outline" onClick={() => setReviewOpen(false)} disabled={generating}>Cancel</Button>
            <Button onClick={handleGenerate} disabled={generating || reviewTotals.count === 0}>
              {generating ? <><Loader2 className="h-4 w-4 mr-2 animate-spin" /> Generating...</> : <><FileText className="h-4 w-4 mr-2" /> Generate Invoice</>}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
