import { useState, useEffect, useMemo } from "react";
import { supabase } from "@/integrations/supabase/client";
import { useToast } from "@/hooks/use-toast";
import { BookOpen, Plus, Search, MoreHorizontal, Edit, Trash2, ChevronRight, CheckSquare, Download, X, Pencil } from "lucide-react";
import RecordImportButton from "@/components/RecordImportButton";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Checkbox } from "@/components/ui/checkbox";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription } from "@/components/ui/dialog";
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 { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog";
import { invokeEdgeFunction } from "@/lib/edgeFunctionUtils";
import { Loader2 } from "lucide-react";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
import { cn } from "@/lib/utils";

const accountTypes = ["asset", "liability", "equity", "income", "expense"];

const typeColors: Record<string, string> = {
  asset: "bg-blue-100 text-blue-700",
  liability: "bg-red-100 text-red-700",
  equity: "bg-purple-100 text-purple-700",
  income: "bg-emerald-100 text-emerald-700",
  expense: "bg-amber-100 text-amber-700",
};

export default function ChartOfAccountsPage() {
  const { toast } = useToast();
  const [accounts, setAccounts] = useState<any[]>([]);
  const [associations, setAssociations] = useState<any[]>([]);
  const [loading, setLoading] = useState(true);
  const [search, setSearch] = useState("");
  const [typeFilter, setTypeFilter] = useState("all");
  const [selectedAssocId, setSelectedAssocId] = useState("all");
  const [dialogOpen, setDialogOpen] = useState(false);
  const [editing, setEditing] = useState<any>(null);
  const [form, setForm] = useState({
    account_number: "", account_name: "", account_type: "expense",
    parent_account_id: "", description: "", is_active: true, association_id: "",
    selectedAssociationIds: [] as string[]
  });

  // Bulk selection
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
  const [bulkDeleteOpen, setBulkDeleteOpen] = useState(false);
  const [bulkDeleting, setBulkDeleting] = useState(false);

  // Bulk edit
  const [bulkEditOpen, setBulkEditOpen] = useState(false);
  const [bulkEditing, setBulkEditing] = useState(false);
  const [bulkEdit, setBulkEdit] = useState<{
    account_type: string;
    is_active: string; // "no_change" | "true" | "false"
    accounting_system: string; // "no_change" | "buildium" | "zoho"
    parent_account_id: string; // "no_change" | "none" | uuid
    associationsMode: "no_change" | "replace" | "add" | "remove";
    associationIds: string[];
  }>({
    account_type: "no_change",
    is_active: "no_change",
    accounting_system: "no_change",
    parent_account_id: "no_change",
    associationsMode: "no_change",
    associationIds: [],
  });

  // Zoho import
  const [zohoImportOpen, setZohoImportOpen] = useState(false);
  const [zohoAccounts, setZohoAccounts] = useState<any[]>([]);
  const [zohoSelectedIds, setZohoSelectedIds] = useState<Set<string>>(new Set());
  const [zohoLoading, setZohoLoading] = useState(false);
  const [zohoImporting, setZohoImporting] = useState(false);
  const [zohoTargetAssocId, setZohoTargetAssocId] = useState("");

  const fetchData = async () => {
    setLoading(true);
    const [acctRes, assocRes] = await Promise.all([
      supabase.from("chart_of_accounts").select("*, associations(name)").order("account_number"),
      supabase.from("associations").select("id, name, zoho_organization_id").eq("status", "active").order("name"),
    ]);
    setAccounts(acctRes.data || []);
    setAssociations(assocRes.data || []);
    setLoading(false);
  };

  // Helper to get association names for an account's association_ids
  const getAssocNames = (account: any) => {
    const ids: string[] = account.association_ids || (account.association_id ? [account.association_id] : []);
    return ids.map(id => associations.find(a => a.id === id)?.name).filter(Boolean);
  };

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

  // Clear selection when filters change
  useEffect(() => { setSelectedIds(new Set()); }, [selectedAssocId, typeFilter, search]);

  const filtered = useMemo(() => {
    const matches = (a: any) => {
      if (selectedAssocId !== "all") {
        const ids: string[] = a.association_ids || (a.association_id ? [a.association_id] : []);
        if (!ids.includes(selectedAssocId)) return false;
      }
      if (typeFilter !== "all" && a.account_type !== typeFilter) return false;
      if (search) {
        const q = search.toLowerCase();
        return a.account_name.toLowerCase().includes(q) || a.account_number.toLowerCase().includes(q);
      }
      return true;
    };
    const direct = accounts.filter(matches);
    // Also include parent accounts of any matched child, even if the parent itself
    // isn't assigned to the selected association — so the hierarchy header shows.
    const byId = new Map(accounts.map(a => [a.id, a]));
    const includedIds = new Set(direct.map(a => a.id));
    direct.forEach(a => {
      let pid = a.parent_account_id;
      while (pid && !includedIds.has(pid)) {
        const parent = byId.get(pid);
        if (!parent) break;
        includedIds.add(parent.id);
        pid = parent.parent_account_id;
      }
    });
    return accounts.filter(a => includedIds.has(a.id));
  }, [accounts, selectedAssocId, typeFilter, search]);

  const hierarchical = useMemo(() => {
    const parentAccounts = filtered.filter(a => !a.parent_account_id);
    const childMap = new Map<string, any[]>();
    filtered.forEach(a => {
      if (a.parent_account_id) {
        if (!childMap.has(a.parent_account_id)) childMap.set(a.parent_account_id, []);
        childMap.get(a.parent_account_id)!.push(a);
      }
    });
    const result: { account: any; depth: number }[] = [];
    const addWithChildren = (acct: any, depth: number) => {
      result.push({ account: acct, depth });
      const children = childMap.get(acct.id) || [];
      children.forEach(c => addWithChildren(c, depth + 1));
    };
    parentAccounts.forEach(a => addWithChildren(a, 0));
    filtered.filter(a => a.parent_account_id && !filtered.find(p => p.id === a.parent_account_id)).forEach(a => {
      if (!result.find(r => r.account.id === a.id)) result.push({ account: a, depth: 0 });
    });
    return result;
  }, [filtered]);

  const allFilteredIds = useMemo(() => new Set(hierarchical.map(h => h.account.id)), [hierarchical]);
  const allSelected = allFilteredIds.size > 0 && [...allFilteredIds].every(id => selectedIds.has(id));

  const toggleSelectAll = () => {
    if (allSelected) {
      setSelectedIds(new Set());
    } else {
      setSelectedIds(new Set(allFilteredIds));
    }
  };

  const toggleSelect = (id: string) => {
    setSelectedIds(prev => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  const handleBulkDelete = async () => {
    setBulkDeleting(true);
    try {
      const ids = [...selectedIds];
      // Delete in batches of 50
      for (let i = 0; i < ids.length; i += 50) {
        const batch = ids.slice(i, i + 50);
        const { error } = await supabase.from("chart_of_accounts").delete().in("id", batch);
        if (error) throw error;
      }
      toast({ title: `Deleted ${ids.length} account(s)` });
      setSelectedIds(new Set());
      fetchData();
    } catch (err: any) {
      toast({ variant: "destructive", title: "Delete failed", description: err.message });
    } finally {
      setBulkDeleting(false);
      setBulkDeleteOpen(false);
    }
  };

  const openBulkEdit = () => {
    setBulkEdit({
      account_type: "no_change",
      is_active: "no_change",
      accounting_system: "no_change",
      parent_account_id: "no_change",
      associationsMode: "no_change",
      associationIds: [],
    });
    setBulkEditOpen(true);
  };

  const toggleBulkEditAssoc = (assocId: string) => {
    setBulkEdit(prev => {
      const next = prev.associationIds.includes(assocId)
        ? prev.associationIds.filter(id => id !== assocId)
        : [...prev.associationIds, assocId];
      return { ...prev, associationIds: next };
    });
  };

  const handleBulkEdit = async () => {
    const ids = [...selectedIds];
    if (ids.length === 0) return;

    // Build base patch from simple fields
    const basePatch: Record<string, any> = {};
    if (bulkEdit.account_type !== "no_change") basePatch.account_type = bulkEdit.account_type;
    if (bulkEdit.is_active !== "no_change") basePatch.is_active = bulkEdit.is_active === "true";
    if (bulkEdit.accounting_system !== "no_change") basePatch.accounting_system = bulkEdit.accounting_system;
    if (bulkEdit.parent_account_id !== "no_change") {
      basePatch.parent_account_id = bulkEdit.parent_account_id === "none" ? null : bulkEdit.parent_account_id;
    }

    const associationsChange = bulkEdit.associationsMode !== "no_change";
    if (Object.keys(basePatch).length === 0 && !associationsChange) {
      toast({ variant: "destructive", title: "No changes selected" });
      return;
    }

    setBulkEditing(true);
    try {
      // Apply simple fields in batched UPDATE
      if (Object.keys(basePatch).length > 0) {
        for (let i = 0; i < ids.length; i += 50) {
          const batch = ids.slice(i, i + 50);
          const { error } = await supabase.from("chart_of_accounts").update(basePatch).in("id", batch);
          if (error) throw error;
        }
      }

      // Apply association changes per-row (set logic differs by mode)
      if (associationsChange) {
        const targets = accounts.filter(a => selectedIds.has(a.id));
        for (const acct of targets) {
          const current: string[] = acct.association_ids || (acct.association_id ? [acct.association_id] : []);
          let next: string[] = current;
          if (bulkEdit.associationsMode === "replace") {
            next = [...bulkEdit.associationIds];
          } else if (bulkEdit.associationsMode === "add") {
            next = Array.from(new Set([...current, ...bulkEdit.associationIds]));
          } else if (bulkEdit.associationsMode === "remove") {
            next = current.filter(id => !bulkEdit.associationIds.includes(id));
          }
          const { error } = await supabase
            .from("chart_of_accounts")
            .update({ association_ids: next, association_id: next[0] || null })
            .eq("id", acct.id);
          if (error) throw error;
        }
      }

      toast({ title: `Updated ${ids.length} account(s)` });
      setSelectedIds(new Set());
      setBulkEditOpen(false);
      fetchData();
    } catch (err: any) {
      toast({ variant: "destructive", title: "Bulk edit failed", description: err.message });
    } finally {
      setBulkEditing(false);
    }
  };

  // Zoho import
  const openZohoImport = () => {
    setZohoTargetAssocId(selectedAssocId !== "all" ? selectedAssocId : associations[0]?.id || "");
    setZohoAccounts([]);
    setZohoSelectedIds(new Set());
    setZohoImportOpen(true);
  };

  const fetchZohoAccounts = async () => {
    if (!zohoTargetAssocId) {
      toast({ variant: "destructive", title: "Select an association first" });
      return;
    }
    setZohoLoading(true);
    try {
      const { data, error } = await invokeEdgeFunction("zoho-books", {
        body: { action: "list_chartofaccounts", params: { association_id: zohoTargetAssocId } },
      });
      if (error) throw error;
      const accts = data?.data?.chartofaccounts || [];
      setZohoAccounts(accts);
      // Pre-select all
      setZohoSelectedIds(new Set(accts.map((a: any) => a.account_id)));
    } catch (err: any) {
      toast({ variant: "destructive", title: "Failed to fetch Zoho accounts", description: err.message });
    } finally {
      setZohoLoading(false);
    }
  };

  const mapZohoAccountType = (zohoType: string): string => {
    const typeMap: Record<string, string> = {
      asset: "asset", other_asset: "asset", fixed_asset: "asset", other_current_asset: "asset",
      cash: "asset", bank: "asset", accounts_receivable: "asset",
      liability: "liability", other_current_liability: "liability", long_term_liability: "liability",
      credit_card: "liability", accounts_payable: "liability",
      equity: "equity",
      income: "income", other_income: "income",
      expense: "expense", other_expense: "expense", cost_of_goods_sold: "expense",
    };
    return typeMap[zohoType?.toLowerCase()] || "expense";
  };

  const handleZohoImport = async () => {
    if (zohoSelectedIds.size === 0) {
      toast({ variant: "destructive", title: "No accounts selected" });
      return;
    }
    setZohoImporting(true);
    try {
      const selected = zohoAccounts.filter((a: any) => zohoSelectedIds.has(a.account_id));
      const rows = selected.map((a: any) => ({
        association_id: zohoTargetAssocId,
        association_ids: [zohoTargetAssocId],
        account_number: a.account_number || String(a.account_id),
        account_name: a.account_name,
        account_type: mapZohoAccountType(a.account_type),
        description: a.description || null,
        is_active: a.is_active !== false,
        accounting_system: "zoho",
      }));

      // Unique index is (account_number, accounting_system). For each row, if it
      // already exists, append the target association to association_ids; otherwise insert.
      for (const row of rows) {
        const { data: existing, error: selErr } = await supabase
          .from("chart_of_accounts")
          .select("id, association_ids")
          .eq("account_number", row.account_number)
          .eq("accounting_system", "zoho")
          .maybeSingle();
        if (selErr) throw selErr;

        if (existing) {
          const merged = Array.from(new Set([...(existing.association_ids || []), zohoTargetAssocId]));
          const { error: updErr } = await supabase
            .from("chart_of_accounts")
            .update({
              association_ids: merged,
              account_name: row.account_name,
              account_type: row.account_type,
              description: row.description,
              is_active: row.is_active,
            })
            .eq("id", existing.id);
          if (updErr) throw updErr;
        } else {
          const { error: insErr } = await supabase.from("chart_of_accounts").insert(row);
          if (insErr) throw insErr;
        }
      }

      toast({ title: `Imported ${rows.length} account(s) from Zoho` });
      setZohoImportOpen(false);
      fetchData();
    } catch (err: any) {
      toast({ variant: "destructive", title: "Import failed", description: err.message });
    } finally {
      setZohoImporting(false);
    }
  };

  const toggleZohoSelect = (id: string) => {
    setZohoSelectedIds(prev => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  const toggleZohoSelectAll = () => {
    if (zohoSelectedIds.size === zohoAccounts.length) {
      setZohoSelectedIds(new Set());
    } else {
      setZohoSelectedIds(new Set(zohoAccounts.map((a: any) => a.account_id)));
    }
  };

  const openNew = () => {
    setEditing(null);
    const defaultAssocIds = selectedAssocId !== "all" ? [selectedAssocId] : [];
    setForm({
      account_number: "", account_name: "", account_type: "expense",
      parent_account_id: "", description: "", is_active: true,
      association_id: defaultAssocIds[0] || associations[0]?.id || "",
      selectedAssociationIds: defaultAssocIds.length > 0 ? defaultAssocIds : (associations[0]?.id ? [associations[0].id] : [])
    });
    setDialogOpen(true);
  };

  const openEdit = (a: any) => {
    setEditing(a);
    const assocIds: string[] = a.association_ids || (a.association_id ? [a.association_id] : []);
    setForm({
      account_number: a.account_number, account_name: a.account_name,
      account_type: a.account_type, parent_account_id: a.parent_account_id || "",
      description: a.description || "", is_active: a.is_active,
      association_id: a.association_id,
      selectedAssociationIds: assocIds
    });
    setDialogOpen(true);
  };

  const toggleFormAssociation = (assocId: string) => {
    setForm(prev => {
      const current = prev.selectedAssociationIds;
      const next = current.includes(assocId)
        ? current.filter(id => id !== assocId)
        : [...current, assocId];
      return { ...prev, selectedAssociationIds: next, association_id: next[0] || "" };
    });
  };

  const handleSave = async () => {
    if (!form.account_number || !form.account_name || form.selectedAssociationIds.length === 0) {
      toast({ variant: "destructive", title: "Account number, name, and at least one association are required" });
      return;
    }
    const payload = {
      account_number: form.account_number,
      account_name: form.account_name,
      account_type: form.account_type,
      parent_account_id: form.parent_account_id || null,
      description: form.description || null,
      is_active: form.is_active,
      association_id: form.selectedAssociationIds[0],
      association_ids: form.selectedAssociationIds,
    };
    if (editing) {
      await supabase.from("chart_of_accounts").update(payload).eq("id", editing.id);
      toast({ title: "Account updated" });
    } else {
      await supabase.from("chart_of_accounts").insert(payload);
      toast({ title: "Account created" });
    }
    setDialogOpen(false);
    fetchData();
  };

  const handleDelete = async (id: string) => {
    await supabase.from("chart_of_accounts").delete().eq("id", id);
    toast({ title: "Account deleted" });
    fetchData();
  };

  const parentOptions = accounts.filter(a =>
    form.association_id ? a.association_id === form.association_id : true
  ).filter(a => a.id !== editing?.id);

  const typeCounts = accounts.reduce((acc: Record<string, number>, a) => {
    acc[a.account_type] = (acc[a.account_type] || 0) + 1;
    return acc;
  }, {});

  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"><BookOpen className="h-6 w-6 text-primary" /> Chart of Accounts</h1>
          <p className="text-sm text-muted-foreground mt-1">Manage your account structure for each association.</p>
        </div>
        <div className="flex gap-2">
          <RecordImportButton
            title="Import Chart of Accounts"
            description="Upload a CSV or Excel file with account records."
            expectedColumns={[
              { key: "account_number", label: "Account Number", required: true },
              { key: "account_name", label: "Account Name", required: true },
              { key: "account_type", label: "Account Type", required: true },
              { key: "description", label: "Description" },
            ]}
            onImport={async (rows) => {
              const assocId = selectedAssocId !== "all" ? selectedAssocId : associations[0]?.id;
              if (!assocId) throw new Error("Select or create an association first");
              const payload = rows.map(r => ({
                account_number: r.account_number || "",
                account_name: r.account_name || "Unknown",
                account_type: r.account_type || "expense",
                description: r.description || null,
                association_id: assocId,
              }));
              const { error } = await supabase.from("chart_of_accounts").insert(payload);
              if (error) throw error;
              toast({ title: `Imported ${rows.length} accounts` });
              fetchData();
            }}
            templateFileName="chart_of_accounts_template.xlsx"
          />
          <Button variant="outline" className="gap-2" onClick={openZohoImport}>
            <Download className="h-4 w-4" /> Import from Zoho
          </Button>
          <Button className="gap-2" onClick={openNew}><Plus className="h-4 w-4" /> Add Account</Button>
        </div>
      </div>

      {/* Bulk action bar */}
      {selectedIds.size > 0 && (
        <div className="flex items-center gap-3 bg-primary/5 border border-primary/20 rounded-lg px-4 py-3">
          <CheckSquare className="h-4 w-4 text-primary" />
          <span className="text-sm font-medium">{selectedIds.size} account(s) selected</span>
          <div className="flex gap-2 ml-auto">
            <Button variant="outline" size="sm" className="gap-2" onClick={openBulkEdit}>
              <Pencil className="h-4 w-4" /> Edit Selected
            </Button>
            <Button variant="destructive" size="sm" className="gap-2" onClick={() => setBulkDeleteOpen(true)}>
              <Trash2 className="h-4 w-4" /> Delete Selected
            </Button>
            <Button variant="ghost" size="sm" onClick={() => setSelectedIds(new Set())}>Clear</Button>
          </div>
        </div>
      )}

      {/* Type summary */}
      <div className="flex gap-2 flex-wrap">
        {accountTypes.map(t => (
          <Badge key={t} variant="outline" className={`${typeColors[t]} cursor-pointer`} onClick={() => setTypeFilter(typeFilter === t ? "all" : t)}>
            {t.charAt(0).toUpperCase() + t.slice(1)} ({typeCounts[t] || 0})
          </Badge>
        ))}
      </div>

      <div className="flex gap-2 flex-wrap">
        <Select value={selectedAssocId} onValueChange={setSelectedAssocId}>
          <SelectTrigger className="w-48"><SelectValue placeholder="All Associations" /></SelectTrigger>
          <SelectContent>
            <SelectItem value="all">All Associations</SelectItem>
            {associations.map(a => <SelectItem key={a.id} value={a.id}>{a.name}</SelectItem>)}
          </SelectContent>
        </Select>
        <div className="relative flex-1 max-w-md">
          <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
          <Input placeholder="Search accounts..." className="pl-10" value={search} onChange={(e) => setSearch(e.target.value)} />
        </div>
      </div>

      {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>
      ) : hierarchical.length === 0 ? (
        <Card><CardContent className="py-12 text-center text-muted-foreground">No accounts found.</CardContent></Card>
      ) : (
        <Card>
          <Table>
            <TableHeader>
              <TableRow>
                <TableHead className="w-12">
                  <Checkbox checked={allSelected} onCheckedChange={toggleSelectAll} />
                </TableHead>
                <TableHead>Account #</TableHead>
                <TableHead>Account Name</TableHead>
                <TableHead>Type</TableHead>
                <TableHead>Association</TableHead>
                <TableHead>Status</TableHead>
                <TableHead className="w-12" />
              </TableRow>
            </TableHeader>
            <TableBody>
              {hierarchical.map(({ account: a, depth }) => (
                <TableRow key={a.id} className={!a.is_active ? "opacity-50" : ""}>
                  <TableCell>
                    <Checkbox checked={selectedIds.has(a.id)} onCheckedChange={() => toggleSelect(a.id)} />
                  </TableCell>
                  <TableCell className="font-mono font-medium">{a.account_number}</TableCell>
                  <TableCell>
                    <div className="flex items-center" style={{ paddingLeft: `${depth * 24}px` }}>
                      {depth > 0 && <ChevronRight className="h-3 w-3 text-muted-foreground mr-1" />}
                      <span className="font-medium">{a.account_name}</span>
                    </div>
                  </TableCell>
                  <TableCell><Badge variant="outline" className={typeColors[a.account_type] || ""}>{a.account_type}</Badge></TableCell>
                  <TableCell>
                    <div className="flex flex-wrap gap-1">
                      {getAssocNames(a).map((name, i) => (
                        <Badge key={i} variant="outline" className="text-[10px] py-0">{name}</Badge>
                      ))}
                      {getAssocNames(a).length === 0 && "—"}
                    </div>
                  </TableCell>
                  <TableCell>
                    <Badge variant="outline" className={a.is_active ? "bg-emerald-100 text-emerald-700" : "bg-muted text-muted-foreground"}>
                      {a.is_active ? "Active" : "Inactive"}
                    </Badge>
                  </TableCell>
                  <TableCell>
                    <DropdownMenu>
                      <DropdownMenuTrigger asChild><Button variant="ghost" size="icon" className="h-8 w-8"><MoreHorizontal className="h-4 w-4" /></Button></DropdownMenuTrigger>
                      <DropdownMenuContent align="end">
                        <DropdownMenuItem onClick={() => openEdit(a)}><Edit className="h-4 w-4 mr-2" /> Edit</DropdownMenuItem>
                        <DropdownMenuItem className="text-destructive" onClick={() => handleDelete(a.id)}><Trash2 className="h-4 w-4 mr-2" /> Delete</DropdownMenuItem>
                      </DropdownMenuContent>
                    </DropdownMenu>
                  </TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
        </Card>
      )}

      {/* Bulk Delete Confirmation */}
      <AlertDialog open={bulkDeleteOpen} onOpenChange={setBulkDeleteOpen}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>Delete {selectedIds.size} account(s)?</AlertDialogTitle>
            <AlertDialogDescription>
              This action cannot be undone. Accounts linked to transactions may fail to delete.
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel disabled={bulkDeleting}>Cancel</AlertDialogCancel>
            <AlertDialogAction onClick={handleBulkDelete} disabled={bulkDeleting} className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
              {bulkDeleting ? <Loader2 className="h-4 w-4 animate-spin mr-2" /> : null}
              Delete {selectedIds.size} Account(s)
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>

      {/* Bulk Edit Dialog */}
      <Dialog open={bulkEditOpen} onOpenChange={setBulkEditOpen}>
        <DialogContent className="max-w-xl">
          <DialogHeader>
            <DialogTitle>Bulk edit {selectedIds.size} account(s)</DialogTitle>
            <DialogDescription>
              Only fields you change will be applied. Leave a field as "No change" to keep its current value.
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-4">
            <div className="grid grid-cols-2 gap-4">
              <div>
                <Label>Account Type</Label>
                <Select value={bulkEdit.account_type} onValueChange={(v) => setBulkEdit(p => ({ ...p, account_type: v }))}>
                  <SelectTrigger><SelectValue /></SelectTrigger>
                  <SelectContent>
                    <SelectItem value="no_change">No change</SelectItem>
                    {accountTypes.map(t => <SelectItem key={t} value={t}>{t.charAt(0).toUpperCase() + t.slice(1)}</SelectItem>)}
                  </SelectContent>
                </Select>
              </div>
              <div>
                <Label>Status</Label>
                <Select value={bulkEdit.is_active} onValueChange={(v) => setBulkEdit(p => ({ ...p, is_active: v }))}>
                  <SelectTrigger><SelectValue /></SelectTrigger>
                  <SelectContent>
                    <SelectItem value="no_change">No change</SelectItem>
                    <SelectItem value="true">Active</SelectItem>
                    <SelectItem value="false">Inactive</SelectItem>
                  </SelectContent>
                </Select>
              </div>
              <div>
                <Label>Accounting System</Label>
                <Select value={bulkEdit.accounting_system} onValueChange={(v) => setBulkEdit(p => ({ ...p, accounting_system: v }))}>
                  <SelectTrigger><SelectValue /></SelectTrigger>
                  <SelectContent>
                    <SelectItem value="no_change">No change</SelectItem>
                    <SelectItem value="buildium">Buildium</SelectItem>
                    <SelectItem value="zoho">Zoho</SelectItem>
                  </SelectContent>
                </Select>
              </div>
              <div>
                <Label>Parent Account</Label>
                <Select value={bulkEdit.parent_account_id} onValueChange={(v) => setBulkEdit(p => ({ ...p, parent_account_id: v }))}>
                  <SelectTrigger><SelectValue /></SelectTrigger>
                  <SelectContent>
                    <SelectItem value="no_change">No change</SelectItem>
                    <SelectItem value="none">None (top-level)</SelectItem>
                    {accounts
                      .filter(a => !selectedIds.has(a.id))
                      .map(a => <SelectItem key={a.id} value={a.id}>{a.account_number} - {a.account_name}</SelectItem>)}
                  </SelectContent>
                </Select>
              </div>
            </div>

            <div className="border rounded-lg p-3 space-y-3">
              <div>
                <Label>Association Assignment</Label>
                <Select
                  value={bulkEdit.associationsMode}
                  onValueChange={(v: any) => setBulkEdit(p => ({ ...p, associationsMode: v }))}
                >
                  <SelectTrigger><SelectValue /></SelectTrigger>
                  <SelectContent>
                    <SelectItem value="no_change">No change</SelectItem>
                    <SelectItem value="replace">Replace with selected</SelectItem>
                    <SelectItem value="add">Add selected to existing</SelectItem>
                    <SelectItem value="remove">Remove selected from existing</SelectItem>
                  </SelectContent>
                </Select>
              </div>

              {bulkEdit.associationsMode !== "no_change" && (
                <div>
                  <Label className="text-xs text-muted-foreground">Pick associations</Label>
                  <Popover>
                    <PopoverTrigger asChild>
                      <Button variant="outline" className="w-full justify-between h-auto min-h-[40px] font-normal">
                        <div className="flex flex-wrap gap-1">
                          {bulkEdit.associationIds.length > 0
                            ? bulkEdit.associationIds.map(id => {
                                const assoc = associations.find(a => a.id === id);
                                return assoc ? (
                                  <Badge key={id} variant="secondary" className="text-xs gap-1">
                                    {assoc.name}
                                    <X className="h-3 w-3 cursor-pointer" onClick={(e) => { e.stopPropagation(); toggleBulkEditAssoc(id); }} />
                                  </Badge>
                                ) : null;
                              })
                            : <span className="text-muted-foreground">Select associations...</span>}
                        </div>
                      </Button>
                    </PopoverTrigger>
                    <PopoverContent className="w-[300px] p-0" align="start">
                      <Command>
                        <CommandInput placeholder="Search associations..." />
                        <CommandList>
                          <CommandEmpty>No associations found.</CommandEmpty>
                          <CommandGroup>
                            {associations.map(a => (
                              <CommandItem key={a.id} onSelect={() => toggleBulkEditAssoc(a.id)} className="flex items-center gap-2">
                                <Checkbox checked={bulkEdit.associationIds.includes(a.id)} />
                                <span>{a.name}</span>
                              </CommandItem>
                            ))}
                          </CommandGroup>
                        </CommandList>
                      </Command>
                    </PopoverContent>
                  </Popover>
                </div>
              )}
            </div>
          </div>

          <DialogFooter>
            <Button variant="outline" onClick={() => setBulkEditOpen(false)} disabled={bulkEditing}>Cancel</Button>
            <Button onClick={handleBulkEdit} disabled={bulkEditing} className="gap-2">
              {bulkEditing && <Loader2 className="h-4 w-4 animate-spin" />}
              Apply to {selectedIds.size} account(s)
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Add/Edit Dialog */}
      <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
        <DialogContent>
          <DialogHeader><DialogTitle>{editing ? "Edit" : "Add"} Account</DialogTitle></DialogHeader>
          <div className="space-y-4">
            <div>
              <Label>Associations</Label>
              <Popover>
                <PopoverTrigger asChild>
                  <Button variant="outline" className="w-full justify-between h-auto min-h-[40px] font-normal">
                    <div className="flex flex-wrap gap-1">
                      {form.selectedAssociationIds.length > 0
                        ? form.selectedAssociationIds.map(id => {
                            const assoc = associations.find(a => a.id === id);
                            return assoc ? (
                              <Badge key={id} variant="secondary" className="text-xs gap-1">
                                {assoc.name}
                                <X className="h-3 w-3 cursor-pointer" onClick={(e) => { e.stopPropagation(); toggleFormAssociation(id); }} />
                              </Badge>
                            ) : null;
                          })
                        : <span className="text-muted-foreground">Select associations...</span>
                      }
                    </div>
                  </Button>
                </PopoverTrigger>
                <PopoverContent className="w-[300px] p-0" align="start">
                  <Command>
                    <CommandInput placeholder="Search associations..." />
                    <CommandList>
                      <CommandEmpty>No associations found.</CommandEmpty>
                      <CommandGroup>
                        {associations.map(a => (
                          <CommandItem
                            key={a.id}
                            onSelect={() => toggleFormAssociation(a.id)}
                            className="flex items-center gap-2"
                          >
                            <Checkbox checked={form.selectedAssociationIds.includes(a.id)} />
                            <span>{a.name}</span>
                          </CommandItem>
                        ))}
                      </CommandGroup>
                    </CommandList>
                  </Command>
                </PopoverContent>
              </Popover>
            </div>
            <div className="grid grid-cols-2 gap-4">
              <div><Label>Account Number</Label><Input value={form.account_number} onChange={(e) => setForm({ ...form, account_number: e.target.value })} placeholder="e.g. 1000" /></div>
              <div>
                <Label>Account Type</Label>
                <Select value={form.account_type} onValueChange={(v) => setForm({ ...form, account_type: v })}>
                  <SelectTrigger><SelectValue /></SelectTrigger>
                  <SelectContent>{accountTypes.map(t => <SelectItem key={t} value={t}>{t.charAt(0).toUpperCase() + t.slice(1)}</SelectItem>)}</SelectContent>
                </Select>
              </div>
            </div>
            <div><Label>Account Name</Label><Input value={form.account_name} onChange={(e) => setForm({ ...form, account_name: e.target.value })} /></div>
            <div>
              <Label>Parent Account (optional)</Label>
              <Select value={form.parent_account_id || "none"} onValueChange={(v) => setForm({ ...form, parent_account_id: v === "none" ? "" : v })}>
                <SelectTrigger><SelectValue placeholder="None (top-level)" /></SelectTrigger>
                <SelectContent>
                  <SelectItem value="none">None (top-level)</SelectItem>
                  {parentOptions.map(a => <SelectItem key={a.id} value={a.id}>{a.account_number} - {a.account_name}</SelectItem>)}
                </SelectContent>
              </Select>
            </div>
            <div><Label>Description</Label><Input value={form.description} onChange={(e) => setForm({ ...form, description: e.target.value })} /></div>
          </div>
          <DialogFooter><Button onClick={handleSave}>{editing ? "Update" : "Create"}</Button></DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Zoho Import Dialog */}
      <Dialog open={zohoImportOpen} onOpenChange={setZohoImportOpen}>
        <DialogContent className="max-w-2xl max-h-[80vh] flex flex-col">
          <DialogHeader>
            <DialogTitle>Import Accounts from Zoho</DialogTitle>
            <DialogDescription>
              Select an association, fetch its Zoho chart of accounts, then choose which to import as budget categories.
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-4 flex-1 overflow-hidden flex flex-col">
            <div className="flex gap-3 items-end">
              <div className="flex-1">
                <Label>Association</Label>
                <Select value={zohoTargetAssocId} onValueChange={setZohoTargetAssocId}>
                  <SelectTrigger><SelectValue placeholder="Select association" /></SelectTrigger>
                  <SelectContent>
                    {associations.map(a => (
                      <SelectItem key={a.id} value={a.id}>
                        {a.name} {a.zoho_organization_id ? "✓" : ""}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>
              <Button onClick={fetchZohoAccounts} disabled={zohoLoading || !zohoTargetAssocId} variant="outline" className="gap-2">
                {zohoLoading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Download className="h-4 w-4" />}
                Fetch
              </Button>
            </div>

            {zohoAccounts.length > 0 && (
              <div className="flex-1 overflow-auto border rounded-lg">
                <Table>
                  <TableHeader>
                    <TableRow>
                      <TableHead className="w-12">
                        <Checkbox
                          checked={zohoSelectedIds.size === zohoAccounts.length && zohoAccounts.length > 0}
                          onCheckedChange={toggleZohoSelectAll}
                        />
                      </TableHead>
                      <TableHead>Account Name</TableHead>
                      <TableHead>Account #</TableHead>
                      <TableHead>Type</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {zohoAccounts.map((a: any) => (
                      <TableRow key={a.account_id}>
                        <TableCell>
                          <Checkbox
                            checked={zohoSelectedIds.has(a.account_id)}
                            onCheckedChange={() => toggleZohoSelect(a.account_id)}
                          />
                        </TableCell>
                        <TableCell className="font-medium">{a.account_name}</TableCell>
                        <TableCell className="font-mono text-sm">{a.account_number || "—"}</TableCell>
                        <TableCell>
                          <Badge variant="outline" className={typeColors[mapZohoAccountType(a.account_type)] || ""}>
                            {a.account_type}
                          </Badge>
                        </TableCell>
                      </TableRow>
                    ))}
                  </TableBody>
                </Table>
              </div>
            )}

            {zohoAccounts.length === 0 && !zohoLoading && (
              <div className="text-center py-8 text-muted-foreground text-sm">
                Select an association and click Fetch to load Zoho accounts.
              </div>
            )}
          </div>

          <DialogFooter>
            <Button variant="outline" onClick={() => setZohoImportOpen(false)}>Cancel</Button>
            <Button onClick={handleZohoImport} disabled={zohoImporting || zohoSelectedIds.size === 0} className="gap-2">
              {zohoImporting ? <Loader2 className="h-4 w-4 animate-spin" /> : null}
              Import {zohoSelectedIds.size} Account(s)
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
