import { useState, useEffect } from "react";
import { supabase } from "@/integrations/supabase/client";
import { useToast } from "@/hooks/use-toast";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
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 { Loader2, Save, ArrowRight, Plus, Trash2 } from "lucide-react";

const CHARGE_TYPES = [
  { value: "assessment", label: "Assessment" },
  { value: "late_fee", label: "Late Fee" },
  { value: "interest", label: "Interest" },
  { value: "admin_fee", label: "Admin Fee" },
  { value: "legal_fee", label: "Legal Fee" },
  { value: "violation", label: "Violation Fine" },
  { value: "bank_fee", label: "Bank Fee" },
  { value: "special_assessment", label: "Special Assessment" },
  { value: "Prepayment", label: "Prepayment" },
];

interface GLAccount {
  id: string;
  name: string;
  parentId: string | null;
  depth: number;
}

interface MappingRow {
  charge_type: string;
  buildium_gl_account_id: string;
  buildium_gl_account_name: string;
  amount_min: number | null;
  amount_max: number | null;
  custom_description: string;
}

interface Props {
  associations: { id: string; name: string }[];
}

export default function BuildiumGLMappingCard({ associations }: Props) {
  const { toast } = useToast();
  const [selectedAssociation, setSelectedAssociation] = useState("");
  const [mappings, setMappings] = useState<MappingRow[]>([]);
  const [glAccounts, setGlAccounts] = useState<GLAccount[]>([]);
  const [loading, setLoading] = useState(false);
  const [saving, setSaving] = useState(false);
  const [fetchingGL, setFetchingGL] = useState(false);

  useEffect(() => {
    if (!selectedAssociation) { setMappings([]); return; }
    loadMappings(selectedAssociation);
  }, [selectedAssociation]);

  useEffect(() => {
    if (!selectedAssociation) { setGlAccounts([]); return; }
    loadGLAccounts(selectedAssociation);
  }, [selectedAssociation]);

  const loadMappings = async (assocId: string) => {
    setLoading(true);
    try {
      const { data, error } = await supabase
        .from("buildium_gl_mappings")
        .select("charge_type, buildium_gl_account_id, buildium_gl_account_name, amount_min, amount_max, custom_description")
        .eq("association_id", assocId);
      if (error) throw error;
      const rows: MappingRow[] = (data || []).map((m: any) => ({
        charge_type: m.charge_type,
        buildium_gl_account_id: m.buildium_gl_account_id,
        buildium_gl_account_name: m.buildium_gl_account_name || "",
        amount_min: m.amount_min ?? null,
        amount_max: m.amount_max ?? null,
        custom_description: m.custom_description || "",
      }));
      // Ensure at least one row per charge type
      for (const ct of CHARGE_TYPES) {
        if (!rows.some((r) => r.charge_type === ct.value)) {
          rows.push({ charge_type: ct.value, buildium_gl_account_id: "", buildium_gl_account_name: "", amount_min: null, amount_max: null, custom_description: "" });
        }
      }
      // Sort by charge type order, then by amount_min
      rows.sort((a, b) => {
        const ai = CHARGE_TYPES.findIndex((c) => c.value === a.charge_type);
        const bi = CHARGE_TYPES.findIndex((c) => c.value === b.charge_type);
        if (ai !== bi) return ai - bi;
        return (a.amount_min ?? -1) - (b.amount_min ?? -1);
      });
      setMappings(rows);
    } catch (err: any) {
      toast({ variant: "destructive", title: "Error loading mappings", description: err.message });
    } finally {
      setLoading(false);
    }
  };

  const loadGLAccounts = async (assocId: string) => {
    setFetchingGL(true);
    try {
      const { data, error } = await supabase.functions.invoke("buildium-sync", {
        body: { syncType: "gl_accounts", selectedAssociationIds: [assocId] },
      });
      if (error) throw error;

      const result: GLAccount[] = (data?.gl_accounts || []).map((gl: any) => ({
        id: String(gl.id),
        name: [gl.account_number, gl.name].filter(Boolean).join(" - "),
        parentId: null,
        depth: 0,
      }));

      setGlAccounts(result);
    } catch (err: any) {
      console.warn("Error loading GL accounts:", err.message);
      setGlAccounts([]);
    } finally {
      setFetchingGL(false);
    }
  };

  const updateRow = (index: number, field: keyof MappingRow, value: any) => {
    setMappings((prev) => {
      const next = [...prev];
      const row = { ...next[index] };
      if (field === "buildium_gl_account_id" && glAccounts.length > 0) {
        const gl = glAccounts.find((g) => String(g.id) === value);
        row.buildium_gl_account_id = value;
        row.buildium_gl_account_name = gl?.name || "";
      } else {
        (row as any)[field] = value;
      }
      next[index] = row;
      // Propagate custom_description to all rows sharing the same charge_type
      if (field === "custom_description") {
        for (let i = 0; i < next.length; i++) {
          if (i !== index && next[i].charge_type === row.charge_type) {
            next[i] = { ...next[i], custom_description: value };
          }
        }
      }
      return next;
    });
  };

  const addThresholdRow = (chargeType: string) => {
    setMappings((prev) => {
      const lastIdx = prev.map((r, i) => r.charge_type === chargeType ? i : -1).filter((i) => i >= 0).pop() ?? prev.length - 1;
      const newRow: MappingRow = {
        charge_type: chargeType,
        buildium_gl_account_id: "",
        buildium_gl_account_name: "",
        amount_min: null,
        amount_max: null,
        custom_description: "",
      };
      const next = [...prev];
      next.splice(lastIdx + 1, 0, newRow);
      return next;
    });
  };

  const removeRow = (index: number) => {
    setMappings((prev) => {
      const row = prev[index];
      const countForType = prev.filter((r) => r.charge_type === row.charge_type).length;
      if (countForType <= 1) {
        // Don't remove last row, just clear it
        const next = [...prev];
        next[index] = { ...row, buildium_gl_account_id: "", buildium_gl_account_name: "", amount_min: null, amount_max: null, custom_description: "" };
        return next;
      }
      return prev.filter((_, i) => i !== index);
    });
  };

  const saveMappings = async () => {
    if (!selectedAssociation) return;
    setSaving(true);
    try {
      await supabase.from("buildium_gl_mappings").delete().eq("association_id", selectedAssociation);

      const inserts = mappings
        .filter((m) => m.buildium_gl_account_id)
        .map((m) => ({
          association_id: selectedAssociation,
          charge_type: m.charge_type,
          buildium_gl_account_id: m.buildium_gl_account_id,
          buildium_gl_account_name: m.buildium_gl_account_name || null,
          amount_min: m.amount_min,
          amount_max: m.amount_max,
          custom_description: m.charge_type === "interest" ? null : (m.custom_description?.trim() || null),
        }));

      if (inserts.length > 0) {
        const { error } = await supabase.from("buildium_gl_mappings").insert(inserts);
        if (error) throw error;
      }

      toast({ title: "Mappings saved", description: `${inserts.length} GL account mapping(s) saved.` });
    } catch (err: any) {
      toast({ variant: "destructive", title: "Save failed", description: err.message });
    } finally {
      setSaving(false);
    }
  };

  const mappedCount = mappings.filter((m) => m.buildium_gl_account_id).length;

  // Group rows by charge type for rendering
  const groupedByType: Record<string, { label: string; rows: { row: MappingRow; globalIndex: number }[] }> = {};
  mappings.forEach((row, gi) => {
    if (!groupedByType[row.charge_type]) {
      const ct = CHARGE_TYPES.find((c) => c.value === row.charge_type);
      groupedByType[row.charge_type] = { label: ct?.label || row.charge_type, rows: [] };
    }
    groupedByType[row.charge_type].rows.push({ row, globalIndex: gi });
  });

  return (
    <Card>
      <CardHeader>
        <CardTitle className="text-lg">Buildium GL Account Mapping</CardTitle>
        <CardDescription>
          Map charge types to Buildium GL accounts. Use the "+" button to add amount-based thresholds (e.g. assessments ≤ $100 → GL A, assessments &gt; $100 → GL B).
        </CardDescription>
      </CardHeader>
      <CardContent className="space-y-4">
        <div className="flex items-center gap-3">
          <Select value={selectedAssociation} onValueChange={setSelectedAssociation}>
            <SelectTrigger className="w-[300px]">
              <SelectValue placeholder="Select association..." />
            </SelectTrigger>
            <SelectContent>
              {associations.map((a) => (
                <SelectItem key={a.id} value={a.id}>{a.name}</SelectItem>
              ))}
            </SelectContent>
          </Select>
          {selectedAssociation && (
            <Badge variant="outline" className="text-xs">
              {mappedCount} mapping(s)
            </Badge>
          )}
        </div>

        {selectedAssociation && (
          <>
            {loading ? (
              <div className="flex items-center gap-2 text-sm text-muted-foreground py-4">
                <Loader2 className="h-4 w-4 animate-spin" /> Loading mappings...
              </div>
            ) : (
              <div className="space-y-4">
                {glAccounts.length === 0 && !fetchingGL && (
                  <p className="text-sm text-muted-foreground bg-muted p-3 rounded-lg">
                    No GL accounts found. Sync from Buildium first, or enter GL Account IDs manually.
                  </p>
                )}

                {Object.entries(groupedByType).map(([chargeType, { label, rows }]) => {
                  const hasMultiple = rows.length > 1;
                  return (
                    <div key={chargeType} className="border rounded-lg p-3 space-y-2">
                      <div className="flex items-center justify-between">
                        <Label className="text-sm font-semibold">{label}</Label>
                        <Button
                          variant="ghost"
                          size="sm"
                          className="h-7 gap-1 text-xs text-muted-foreground"
                          onClick={() => addThresholdRow(chargeType)}
                        >
                          <Plus className="h-3 w-3" /> Add threshold
                        </Button>
                      </div>
                      {rows.map(({ row, globalIndex }, ri) => (
                        <div key={ri} className="flex items-center gap-2">
                          {hasMultiple && (
                            <div className="flex items-center gap-1 shrink-0">
                              <Input
                                type="number"
                                placeholder="Min $"
                                className="w-[80px] h-8 text-xs"
                                value={row.amount_min ?? ""}
                                onChange={(e) => updateRow(globalIndex, "amount_min", e.target.value ? parseFloat(e.target.value) : null)}
                              />
                              <span className="text-xs text-muted-foreground">–</span>
                              <Input
                                type="number"
                                placeholder="Max $"
                                className="w-[80px] h-8 text-xs"
                                value={row.amount_max ?? ""}
                                onChange={(e) => updateRow(globalIndex, "amount_max", e.target.value ? parseFloat(e.target.value) : null)}
                              />
                            </div>
                          )}
                          <ArrowRight className="h-4 w-4 text-muted-foreground shrink-0" />
                          {glAccounts.length > 0 ? (
                            <Select
                              value={row.buildium_gl_account_id || "__none__"}
                              onValueChange={(v) => updateRow(globalIndex, "buildium_gl_account_id", v === "__none__" ? "" : v)}
                            >
                              <SelectTrigger className="flex-1 h-8 text-xs">
                                <SelectValue placeholder="Select GL account..." />
                              </SelectTrigger>
                              <SelectContent>
                                <SelectItem value="__none__">— Not mapped —</SelectItem>
                                {glAccounts.map((gl) => (
                                  <SelectItem key={gl.id} value={String(gl.id)}>
                                    {gl.depth > 0 ? `  ↳ ${gl.name}` : gl.name}
                                  </SelectItem>
                                ))}
                              </SelectContent>
                            </Select>
                          ) : (
                            <Input
                              placeholder="Buildium GL Account ID"
                              value={row.buildium_gl_account_id || ""}
                              onChange={(e) => updateRow(globalIndex, "buildium_gl_account_id", e.target.value)}
                              className="flex-1 h-8 text-xs"
                            />
                          )}
                          {hasMultiple && (
                            <Button variant="ghost" size="icon" className="h-7 w-7 shrink-0" onClick={() => removeRow(globalIndex)}>
                              <Trash2 className="h-3 w-3 text-muted-foreground" />
                            </Button>
                          )}
                        </div>
                      ))}
                      {chargeType !== "interest" && (
                        <div className="pl-6 pt-1">
                          <Input
                            placeholder="Default memo to push to Buildium (optional, max 65 chars)"
                            maxLength={65}
                            className="h-8 text-xs"
                            value={rows[0]?.row.custom_description || ""}
                            onChange={(e) => updateRow(rows[0].globalIndex, "custom_description", e.target.value)}
                          />
                          <p className="text-[10px] text-muted-foreground mt-1">
                            Auto-fills the charge memo for all "{label}" rows when pushing to Buildium. Leave blank to use the entry's own description.
                          </p>
                        </div>
                      )}
                    </div>
                  );
                })}

                <div className="flex justify-end pt-2">
                  <Button onClick={saveMappings} disabled={saving} className="gap-2">
                    {saving ? <Loader2 className="h-4 w-4 animate-spin" /> : <Save className="h-4 w-4" />}
                    Save Mappings
                  </Button>
                </div>
              </div>
            )}
          </>
        )}
      </CardContent>
    </Card>
  );
}
