import { useEffect, useMemo, useState } from "react";
import { z } from "zod";
import { supabase } from "@/integrations/supabase/client";
import { useAuth } from "@/contexts/AuthContext";
import { useToast } from "@/hooks/use-toast";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Switch } from "@/components/ui/switch";
import { Badge } from "@/components/ui/badge";
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Building2, Mail, Phone, Plus, Search, Trash2, Pencil, Loader2, Users, Eye, EyeOff } from "lucide-react";

const directorySchema = z.object({
  display_name: z.string().trim().min(1, "Name is required").max(150),
  title: z.string().trim().max(150).optional(),
  company: z.string().trim().max(150).optional(),
  email: z.string().trim().max(255).optional().refine((value) => !value || z.string().email().safeParse(value).success, "Enter a valid email"),
  phone: z.string().trim().max(50).optional(),
  address: z.string().trim().max(255).optional(),
  category: z.string().trim().min(1, "Category is required").max(80),
  notes: z.string().trim().max(1000).optional(),
  is_published: z.boolean(),
});

type DirectoryEntry = {
  id: string;
  association_id: string;
  owner_id: string | null;
  display_name: string;
  title: string | null;
  company: string | null;
  email: string | null;
  phone: string | null;
  address: string | null;
  category: string;
  notes: string | null;
  is_owner_opt_in: boolean;
  is_published: boolean;
  created_at: string;
};

type DirectoryForm = z.infer<typeof directorySchema>;

const emptyForm: DirectoryForm = {
  display_name: "",
  title: "",
  company: "",
  email: "",
  phone: "",
  address: "",
  category: "Resident",
  notes: "",
  is_published: true,
};

interface Props {
  associationId: string;
  mode?: "admin" | "readonly";
  title?: string;
  description?: string;
}

export default function AssociationDirectoryManager({ associationId, mode = "admin", title = "Directory", description = "Post and manage association directory information." }: Props) {
  const { toast } = useToast();
  const { user } = useAuth();
  const [entries, setEntries] = useState<DirectoryEntry[]>([]);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [dialogOpen, setDialogOpen] = useState(false);
  const [editing, setEditing] = useState<DirectoryEntry | null>(null);
  const [form, setForm] = useState<DirectoryForm>(emptyForm);
  const [query, setQuery] = useState("");
  const [errors, setErrors] = useState<Record<string, string>>({});

  const canManage = mode === "admin";

  useEffect(() => {
    void loadEntries();
  }, [associationId]);

  const loadEntries = async () => {
    setLoading(true);
    let queryBuilder = (supabase as any)
      .from("association_directory_entries")
      .select("*")
      .eq("association_id", associationId)
      .order("category")
      .order("display_name");

    if (!canManage) queryBuilder = queryBuilder.eq("is_published", true);

    const { data, error } = await queryBuilder;
    if (error) toast({ title: "Directory load failed", description: error.message, variant: "destructive" });
    else setEntries(data || []);
    setLoading(false);
  };

  const filteredEntries = useMemo(() => {
    const needle = query.trim().toLowerCase();
    if (!needle) return entries;
    return entries.filter((entry) => [entry.display_name, entry.title, entry.company, entry.email, entry.phone, entry.category]
      .filter(Boolean)
      .some((value) => String(value).toLowerCase().includes(needle)));
  }, [entries, query]);

  const groupedEntries = useMemo(() => filteredEntries.reduce<Record<string, DirectoryEntry[]>>((acc, entry) => {
    const category = entry.category || "Directory";
    acc[category] = [...(acc[category] || []), entry];
    return acc;
  }, {}), [filteredEntries]);

  const openCreate = () => {
    setEditing(null);
    setForm(emptyForm);
    setErrors({});
    setDialogOpen(true);
  };

  const openEdit = (entry: DirectoryEntry) => {
    setEditing(entry);
    setForm({
      display_name: entry.display_name,
      title: entry.title || "",
      company: entry.company || "",
      email: entry.email || "",
      phone: entry.phone || "",
      address: entry.address || "",
      category: entry.category || "Resident",
      notes: entry.notes || "",
      is_published: entry.is_published,
    });
    setErrors({});
    setDialogOpen(true);
  };

  const setField = <K extends keyof DirectoryForm>(key: K, value: DirectoryForm[K]) => setForm((prev) => ({ ...prev, [key]: value }));

  const validate = () => {
    const result = directorySchema.safeParse(form);
    if (result.success) {
      setErrors({});
      return result.data;
    }
    const nextErrors: Record<string, string> = {};
    result.error.issues.forEach((issue) => { nextErrors[String(issue.path[0])] = issue.message; });
    setErrors(nextErrors);
    return null;
  };

  const handleSave = async () => {
    const valid = validate();
    if (!valid) return;

    setSaving(true);
    const payload = {
      association_id: associationId,
      created_by: user?.id || null,
      display_name: valid.display_name,
      title: valid.title || null,
      company: valid.company || null,
      email: valid.email || null,
      phone: valid.phone || null,
      address: valid.address || null,
      category: valid.category,
      notes: valid.notes || null,
      is_published: valid.is_published,
      is_owner_opt_in: false,
    };

    const { error } = editing
      ? await (supabase as any).from("association_directory_entries").update(payload).eq("id", editing.id)
      : await (supabase as any).from("association_directory_entries").insert(payload);

    setSaving(false);
    if (error) {
      toast({ title: "Directory save failed", description: error.message, variant: "destructive" });
      return;
    }
    toast({ title: editing ? "Directory entry updated" : "Directory entry added" });
    setDialogOpen(false);
    void loadEntries();
  };

  const handleDelete = async (entry: DirectoryEntry) => {
    const { error } = await (supabase as any).from("association_directory_entries").delete().eq("id", entry.id);
    if (error) toast({ title: "Delete failed", description: error.message, variant: "destructive" });
    else {
      toast({ title: "Directory entry deleted" });
      setEntries((prev) => prev.filter((item) => item.id !== entry.id));
    }
  };

  const togglePublished = async (entry: DirectoryEntry, checked: boolean) => {
    setEntries((prev) => prev.map((item) => item.id === entry.id ? { ...item, is_published: checked } : item));
    const { error } = await (supabase as any).from("association_directory_entries").update({ is_published: checked }).eq("id", entry.id);
    if (error) {
      setEntries((prev) => prev.map((item) => item.id === entry.id ? entry : item));
      toast({ title: "Visibility update failed", description: error.message, variant: "destructive" });
    }
  };

  return (
    <div className="space-y-5">
      <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
        <div>
          <h3 className="text-base font-semibold text-foreground">{title}</h3>
          <p className="text-sm text-muted-foreground mt-0.5">{description}</p>
        </div>
        {canManage && <Button onClick={openCreate} size="sm" className="gap-1.5"><Plus className="h-4 w-4" /> Add Entry</Button>}
      </div>

      <div className="relative max-w-md">
        <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
        <Input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Search directory..." className="pl-9" maxLength={100} />
      </div>

      {loading ? (
        <div className="flex items-center gap-2 text-sm text-muted-foreground py-8"><Loader2 className="h-4 w-4 animate-spin" /> Loading directory...</div>
      ) : filteredEntries.length === 0 ? (
        <Card><CardContent className="py-12 text-center text-muted-foreground"><Users className="h-8 w-8 mx-auto mb-2 opacity-40" /><p>No directory entries found.</p></CardContent></Card>
      ) : canManage ? (
        <div className="rounded-lg border bg-card overflow-hidden">
          <Table>
            <TableHeader>
              <TableRow>
                <TableHead>Name</TableHead>
                <TableHead>Category</TableHead>
                <TableHead>Contact</TableHead>
                <TableHead>Source</TableHead>
                <TableHead className="w-[110px]">Published</TableHead>
                <TableHead className="w-[96px] text-right">Actions</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {filteredEntries.map((entry) => (
                <TableRow key={entry.id}>
                  <TableCell><EntryName entry={entry} /></TableCell>
                  <TableCell><Badge variant="secondary">{entry.category}</Badge></TableCell>
                  <TableCell><EntryContact entry={entry} /></TableCell>
                  <TableCell><Badge variant={entry.is_owner_opt_in ? "outline" : "default"}>{entry.is_owner_opt_in ? "Owner opt-in" : "Admin"}</Badge></TableCell>
                  <TableCell><Switch checked={entry.is_published} onCheckedChange={(checked) => togglePublished(entry, checked)} /></TableCell>
                  <TableCell>
                    <div className="flex justify-end gap-1">
                      <Button variant="ghost" size="icon" className="h-8 w-8" onClick={() => openEdit(entry)}><Pencil className="h-4 w-4" /></Button>
                      <Button variant="ghost" size="icon" className="h-8 w-8 text-destructive" onClick={() => handleDelete(entry)}><Trash2 className="h-4 w-4" /></Button>
                    </div>
                  </TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
        </div>
      ) : (
        <div className="space-y-5">
          {Object.entries(groupedEntries).map(([category, categoryEntries]) => (
            <Card key={category}>
              <CardHeader className="pb-3"><CardTitle className="text-base">{category}</CardTitle></CardHeader>
              <CardContent className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
                {categoryEntries.map((entry) => <DirectoryCard key={entry.id} entry={entry} />)}
              </CardContent>
            </Card>
          ))}
        </div>
      )}

      <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
        <DialogContent className="sm:max-w-[720px] max-h-[90vh] overflow-y-auto">
          <DialogHeader><DialogTitle>{editing ? "Edit Directory Entry" : "Add Directory Entry"}</DialogTitle></DialogHeader>
          <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
            <Field label="Display Name" error={errors.display_name}><Input value={form.display_name} onChange={(event) => setField("display_name", event.target.value)} maxLength={150} /></Field>
            <Field label="Category" error={errors.category}>
              <Select value={form.category} onValueChange={(value) => setField("category", value)}>
                <SelectTrigger><SelectValue /></SelectTrigger>
                <SelectContent>
                  {['Resident', 'Board Member', 'Committee', 'Vendor', 'Management', 'Emergency', 'Other'].map((category) => <SelectItem key={category} value={category}>{category}</SelectItem>)}
                </SelectContent>
              </Select>
            </Field>
            <Field label="Title" error={errors.title}><Input value={form.title || ""} onChange={(event) => setField("title", event.target.value)} maxLength={150} /></Field>
            <Field label="Company" error={errors.company}><Input value={form.company || ""} onChange={(event) => setField("company", event.target.value)} maxLength={150} /></Field>
            <Field label="Email" error={errors.email}><Input type="email" value={form.email || ""} onChange={(event) => setField("email", event.target.value)} maxLength={255} /></Field>
            <Field label="Phone" error={errors.phone}><Input type="tel" value={form.phone || ""} onChange={(event) => setField("phone", event.target.value)} maxLength={50} /></Field>
            <Field label="Address" error={errors.address} className="sm:col-span-2"><Input value={form.address || ""} onChange={(event) => setField("address", event.target.value)} maxLength={255} /></Field>
            <Field label="Notes" error={errors.notes} className="sm:col-span-2"><Textarea value={form.notes || ""} onChange={(event) => setField("notes", event.target.value)} maxLength={1000} rows={3} /></Field>
            <div className="sm:col-span-2 flex items-center justify-between rounded-lg border bg-background p-3">
              <div className="flex items-center gap-2"><Label>Published</Label>{form.is_published ? <Eye className="h-4 w-4 text-muted-foreground" /> : <EyeOff className="h-4 w-4 text-muted-foreground" />}</div>
              <Switch checked={form.is_published} onCheckedChange={(checked) => setField("is_published", checked)} />
            </div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setDialogOpen(false)}>Cancel</Button>
            <Button onClick={handleSave} disabled={saving}>{saving && <Loader2 className="h-4 w-4 animate-spin mr-1" />}Save Entry</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}

function Field({ label, error, className, children }: { label: string; error?: string; className?: string; children: React.ReactNode }) {
  return <div className={`space-y-1.5 ${className || ""}`}><Label>{label}</Label>{children}{error && <p className="text-xs text-destructive">{error}</p>}</div>;
}

function EntryName({ entry }: { entry: DirectoryEntry }) {
  return <div><p className="font-medium text-foreground">{entry.display_name}</p>{(entry.title || entry.company) && <p className="text-xs text-muted-foreground">{[entry.title, entry.company].filter(Boolean).join(" • ")}</p>}</div>;
}

function EntryContact({ entry }: { entry: DirectoryEntry }) {
  return <div className="space-y-1 text-xs text-muted-foreground">{entry.email && <p className="flex items-center gap-1.5"><Mail className="h-3.5 w-3.5" />{entry.email}</p>}{entry.phone && <p className="flex items-center gap-1.5"><Phone className="h-3.5 w-3.5" />{entry.phone}</p>}{!entry.email && !entry.phone && <span>—</span>}</div>;
}

function DirectoryCard({ entry }: { entry: DirectoryEntry }) {
  return (
    <div className="rounded-lg border bg-background p-4 space-y-3">
      <div className="flex items-start gap-3">
        <div className="h-9 w-9 rounded-md bg-primary/10 flex items-center justify-center shrink-0"><Building2 className="h-4 w-4 text-primary" /></div>
        <EntryName entry={entry} />
      </div>
      <EntryContact entry={entry} />
      {entry.address && <p className="text-xs text-muted-foreground">{entry.address}</p>}
      {entry.notes && <p className="text-sm text-muted-foreground border-t pt-3">{entry.notes}</p>}
    </div>
  );
}
