import { useEffect, useMemo, useState } from "react";
import ImportSpreadsheetDialog from "@/components/ImportSpreadsheetDialog";
import { supabase } from "@/integrations/supabase/client";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
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 { Badge } from "@/components/ui/badge";
import { useToast } from "@/hooks/use-toast";
import { Download, Upload, Users } from "lucide-react";

const PAGE_SIZE = 1000;

const normalize = (value: string | null | undefined) =>
  String(value ?? "").trim().replace(/\s+/g, " ").toLowerCase();

const nullable = (value: string | null | undefined) => {
  const trimmed = String(value ?? "").trim();
  return trimmed ? trimmed : null;
};

const splitName = (value: string | null | undefined) => {
  const parts = String(value ?? "").trim().replace(/\s+/g, " ").split(" ").filter(Boolean);
  return { first_name: parts[0] || "", last_name: parts.slice(1).join(" ") || "" };
};

const ownerKey = (firstName: string, lastName: string, reference: string | null) => {
  const ref = normalize(reference);
  if (!ref) return null;
  return [normalize(firstName), normalize(lastName), ref].join("::");
};

interface Association { id: string; name: string }
interface OwnerLookup {
  id: string;
  first_name: string;
  last_name: string;
  email: string | null;
  phone: string | null;
  property_address: string | null;
  mailing_address: string | null;
  unit_id: string | null;
  account_number: string | null;
  units?: { unit_number: string | null; account_number: string | null } | null;
}

export default function BulkOwnerUpdatesTab() {
  const { toast } = useToast();
  const [associations, setAssociations] = useState<Association[]>([]);
  const [selectedAssociation, setSelectedAssociation] = useState("");
  const [owners, setOwners] = useState<OwnerLookup[]>([]);
  const [loading, setLoading] = useState(false);
  const [importOpen, setImportOpen] = useState(false);
  const [lastResult, setLastResult] = useState<{ updated: number; skipped: number } | null>(null);

  useEffect(() => {
    supabase.from("associations").select("id, name").eq("status", "active").order("name").then(({ data }) => {
      setAssociations(data || []);
      if (data?.[0]) setSelectedAssociation(data[0].id);
    });
  }, []);

  useEffect(() => {
    if (selectedAssociation) fetchOwners();
  }, [selectedAssociation]);

  const fetchOwners = async () => {
    setLoading(true);
    const allOwners: OwnerLookup[] = [];
    for (let from = 0; ; from += PAGE_SIZE) {
      const { data, error } = await supabase
        .from("owners")
        .select("id, first_name, last_name, email, phone, property_address, mailing_address, unit_id, account_number, units(unit_number, account_number)")
        .eq("association_id", selectedAssociation)
        .neq("status", "archived")
        .range(from, from + PAGE_SIZE - 1);
      if (error) {
        toast({ title: "Error loading owners", description: error.message, variant: "destructive" });
        break;
      }
      if (!data?.length) break;
      allOwners.push(...(data as OwnerLookup[]));
      if (data.length < PAGE_SIZE) break;
    }
    setOwners(allOwners);
    setLoading(false);
  };

  const lookupMaps = useMemo(() => {
    const byId = new Map<string, string>();
    const byAccount = new Map<string, string>();
    const byUnit = new Map<string, string>();
    const byProperty = new Map<string, string>();
    owners.forEach((owner) => {
      byId.set(owner.id, owner.id);
      const accountRef = owner.account_number || owner.units?.account_number || null;
      const accountKey = ownerKey(owner.first_name, owner.last_name, accountRef);
      const unitKey = ownerKey(owner.first_name, owner.last_name, owner.units?.unit_number || owner.unit_id);
      const propertyKey = ownerKey(owner.first_name, owner.last_name, owner.property_address);
      if (accountKey && !byAccount.has(accountKey)) byAccount.set(accountKey, owner.id);
      if (unitKey && !byUnit.has(unitKey)) byUnit.set(unitKey, owner.id);
      if (propertyKey && !byProperty.has(propertyKey)) byProperty.set(propertyKey, owner.id);
    });
    return { byId, byAccount, byUnit, byProperty };
  }, [owners]);

  const handleImportUpdates = async (rows: Record<string, string>[]) => {
    const updates: Array<{ id: string; payload: Record<string, unknown> }> = [];
    let skipped = 0;

    rows.forEach((row) => {
      const { first_name, last_name } = splitName(row.owner_name);
      const id = nullable(row.owner_id);
      const matchedId =
        (id && lookupMaps.byId.get(id)) ||
        (nullable(row.account_number) && lookupMaps.byAccount.get(ownerKey(first_name, last_name, nullable(row.account_number)) || "")) ||
        (nullable(row.unit_id) && lookupMaps.byUnit.get(ownerKey(first_name, last_name, nullable(row.unit_id)) || "")) ||
        (nullable(row.property_address) && lookupMaps.byProperty.get(ownerKey(first_name, last_name, nullable(row.property_address)) || ""));

      if (!matchedId) {
        skipped += 1;
        return;
      }

      const payload: Record<string, unknown> = { updated_at: new Date().toISOString() };
      const name = nullable(row.new_owner_name || row.owner_name);
      if (name) Object.assign(payload, splitName(name));
      ["email", "phone", "street_address", "property_address", "mailing_address", "alternate_address_1", "alternate_address_2", "zoho_contact_id"].forEach((field) => {
        const value = nullable(row[field]);
        if (value !== null) payload[field] = value;
      });
      if (nullable(row.balance) !== null) payload.balance = Number(row.balance) || 0;
      updates.push({ id: matchedId, payload });
    });

    for (let i = 0; i < updates.length; i += 25) {
      const results = await Promise.all(updates.slice(i, i + 25).map(({ id, payload }) => supabase.from("owners").update(payload).eq("id", id)));
      const failed = results.find((result) => result.error);
      if (failed?.error) throw failed.error;
    }

    setLastResult({ updated: updates.length, skipped });
    toast({ title: "Bulk update complete", description: `${updates.length} owners updated, ${skipped} rows skipped.` });
    await fetchOwners();
  };

  const handleExportTemplate = async () => {
    const csv = [
      "Owner ID,Owner Name,New Owner Name,Account Number,Unit # or Unit ID,Property Address,Email,Phone,Street Address,Mailing Address,Alternate Address 1,Alternate Address 2,Zoho Contact ID,Balance",
      ...owners.map((owner) => [
        owner.id,
        `${owner.first_name || ""} ${owner.last_name || ""}`.trim(),
        "",
        owner.account_number || owner.units?.account_number || "",
        owner.units?.unit_number || owner.unit_id || "",
        owner.property_address || "",
        owner.email || "",
        owner.phone || "",
        "", "", "", "", "", "",
      ].map((value) => `"${String(value).replace(/"/g, '""')}"`).join(",")),
    ].join("\n");
    const { saveFile } = await import("@/lib/saveFile");
    await saveFile(new Blob([csv], { type: "text/csv" }), { suggestedName: "bulk_owner_updates.csv", mimeType: "text/csv", description: "CSV file" });
  };

  return (
    <div className="space-y-6">
      <p className="text-sm text-muted-foreground">Update owner contact, address, and balance fields from a spreadsheet without creating new owner records.</p>

      <Card>
        <CardHeader><CardTitle>Update Spreadsheet</CardTitle></CardHeader>
        <CardContent className="space-y-4">
          <div className="grid gap-4 md:grid-cols-[minmax(240px,360px)_1fr] md:items-end">
            <div className="space-y-2">
              <Label>Association</Label>
              <Select value={selectedAssociation} onValueChange={setSelectedAssociation}>
                <SelectTrigger><SelectValue placeholder="Select association" /></SelectTrigger>
                <SelectContent>{associations.map((association) => <SelectItem key={association.id} value={association.id}>{association.name}</SelectItem>)}</SelectContent>
              </Select>
            </div>
            <div className="flex flex-wrap gap-2">
              <Button variant="outline" className="gap-2" onClick={handleExportTemplate} disabled={!owners.length}><Download className="h-4 w-4" /> Export Update Template</Button>
              <Button className="gap-2" onClick={() => setImportOpen(true)} disabled={!selectedAssociation}><Upload className="h-4 w-4" /> Import Updates</Button>
            </div>
          </div>
          {lastResult && <Badge variant="secondary">Last import: {lastResult.updated} updated, {lastResult.skipped} skipped</Badge>}
        </CardContent>
      </Card>

      <Card>
        <CardHeader><CardTitle className="flex items-center gap-2"><Users className="h-5 w-5" /> Current Owners ({owners.length})</CardTitle></CardHeader>
        <CardContent>
          <div className="rounded-md border border-border overflow-x-auto">
            <Table>
              <TableHeader><TableRow><TableHead>Owner</TableHead><TableHead>Unit</TableHead><TableHead>Email</TableHead><TableHead>Phone</TableHead><TableHead>Property Address</TableHead></TableRow></TableHeader>
              <TableBody>
                {loading ? <TableRow><TableCell colSpan={5} className="text-center text-muted-foreground py-8">Loading owners...</TableCell></TableRow> : owners.slice(0, 50).map((owner) => (
                  <TableRow key={owner.id}><TableCell className="font-medium">{owner.first_name} {owner.last_name}</TableCell><TableCell>{owner.units?.unit_number || "—"}</TableCell><TableCell>{owner.email || "—"}</TableCell><TableCell>{owner.phone || "—"}</TableCell><TableCell>{owner.property_address || "—"}</TableCell></TableRow>
                ))}
              </TableBody>
            </Table>
          </div>
        </CardContent>
      </Card>

      <ImportSpreadsheetDialog
        open={importOpen}
        onOpenChange={setImportOpen}
        title="Import Owner Updates"
        description="Rows are matched to existing owners by Owner ID first, then owner name plus account, unit, or property address. Blank update fields are ignored."
        templateFileName="bulk_owner_updates_template.xlsx"
        expectedColumns={[
          { key: "owner_id", label: "Owner ID", aliases: ["ID"] },
          { key: "owner_name", label: "Owner Name", required: true, aliases: ["Owner", "Name"] },
          { key: "new_owner_name", label: "New Owner Name" },
          { key: "account_number", label: "Account Number", aliases: ["Account"] },
          { key: "unit_id", label: "Unit # or Unit ID", aliases: ["Unit", "Unit Number", "Unit ID"] },
          { key: "property_address", label: "Property Address" },
          { key: "email", label: "Email" },
          { key: "phone", label: "Phone", aliases: ["Phone Number"] },
          { key: "street_address", label: "Street Address" },
          { key: "mailing_address", label: "Mailing Address" },
          { key: "alternate_address_1", label: "Alternate Address 1" },
          { key: "alternate_address_2", label: "Alternate Address 2" },
          { key: "zoho_contact_id", label: "Zoho Contact ID" },
          { key: "balance", label: "Balance" },
        ]}
        onImport={handleImportUpdates}
      />
    </div>
  );
}
