"use client";

import * as React from "react";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { toast } from "sonner";
import {
  ArrowLeft,
  User,
  Edit2,
  Save,
  X,
  Merge,
  Trash2,
  Loader2,
  FileText,
  Search,
} from "lucide-react";
import { formatDistanceToNow, differenceInDays, format } from "date-fns";

import { Header } from "@/components/layout/header";
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 { Separator } from "@/components/ui/separator";
import { Skeleton } from "@/components/ui/skeleton";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
} from "@/components/ui/dialog";
import { cn } from "@/lib/utils";

type LinkedCard = {
  id: string;
  name: string | null;
  ocrStatus: string;
  reviewStatus: string;
  createdAt: string;
};

type PersonData = {
  id: string;
  firstName: string;
  lastName: string;
  email: string | null;
  cellPhone: string | null;
  fieldData: Record<string, unknown> | null;
  createdAt: string;
  updatedAt: string;
  cards: LinkedCard[];
  _count: { cards: number };
};

type PersonSearchResult = {
  id: string;
  firstName: string;
  lastName: string;
  email: string | null;
  _count: { cards: number };
};

function formatDate(dateStr: string): string {
  const d = new Date(dateStr);
  if (differenceInDays(new Date(), d) < 30) {
    return formatDistanceToNow(d, { addSuffix: true });
  }
  return format(d, "MMM d, yyyy");
}

export default function PersonDetailPage() {
  const params = useParams();
  const router = useRouter();
  const searchParams = useSearchParams();
  const id = params.id as string;

  const [person, setPerson] = React.useState<PersonData | null>(null);
  const [loading, setLoading] = React.useState(true);
  const [notFound, setNotFound] = React.useState(false);

  const [editing, setEditing] = React.useState(false);
  const [editFields, setEditFields] = React.useState({
    firstName: "",
    lastName: "",
    email: "",
    cellPhone: "",
  });
  const [saving, setSaving] = React.useState(false);

  const [mergeOpen, setMergeOpen] = React.useState(false);
  const [mergeSearch, setMergeSearch] = React.useState("");
  const [mergeResults, setMergeResults] = React.useState<PersonSearchResult[]>([]);
  const [mergeSearching, setMergeSearching] = React.useState(false);
  const [mergeTarget, setMergeTarget] = React.useState<PersonSearchResult | null>(null);
  const [merging, setMerging] = React.useState(false);

  const [deleteOpen, setDeleteOpen] = React.useState(false);
  const [deleting, setDeleting] = React.useState(false);

  const fetchPerson = React.useCallback(async () => {
    setLoading(true);
    setNotFound(false);
    try {
      const res = await fetch(`/api/people/${id}`);
      if (res.status === 404) {
        setNotFound(true);
        return;
      }
      if (!res.ok) throw new Error();
      const data = await res.json();
      setPerson(data);
    } catch {
      toast.error("Failed to load person");
    } finally {
      setLoading(false);
    }
  }, [id]);

  React.useEffect(() => {
    fetchPerson();
  }, [fetchPerson]);

  React.useEffect(() => {
    if (searchParams.get("action") === "merge") {
      setMergeOpen(true);
    }
  }, [searchParams]);

  const startEditing = () => {
    if (!person) return;
    setEditFields({
      firstName: person.firstName,
      lastName: person.lastName,
      email: person.email ?? "",
      cellPhone: person.cellPhone ?? "",
    });
    setEditing(true);
  };

  const cancelEditing = () => {
    setEditing(false);
  };

  const handleSave = async () => {
    setSaving(true);
    try {
      const res = await fetch(`/api/people/${id}`, {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(editFields),
      });
      if (!res.ok) {
        const err = await res.json();
        throw new Error(err.error || "Failed to save");
      }
      toast.success("Person updated");
      setEditing(false);
      fetchPerson();
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Failed to save");
    } finally {
      setSaving(false);
    }
  };

  React.useEffect(() => {
    if (!mergeOpen) {
      setMergeSearch("");
      setMergeResults([]);
      setMergeTarget(null);
      return;
    }
  }, [mergeOpen]);

  React.useEffect(() => {
    if (!mergeSearch.trim()) {
      setMergeResults([]);
      return;
    }
    const timer = setTimeout(async () => {
      setMergeSearching(true);
      try {
        const res = await fetch(
          `/api/people?search=${encodeURIComponent(mergeSearch)}&limit=10`
        );
        if (!res.ok) throw new Error();
        const data = await res.json();
        setMergeResults(
          (data.people as PersonSearchResult[]).filter((p) => p.id !== id)
        );
      } catch {
        // ignore search errors
      } finally {
        setMergeSearching(false);
      }
    }, 300);
    return () => clearTimeout(timer);
  }, [mergeSearch, id]);

  const handleMerge = async () => {
    if (!mergeTarget) return;
    setMerging(true);
    try {
      const res = await fetch(`/api/people/${id}/merge`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ targetPersonId: mergeTarget.id }),
      });
      if (!res.ok) {
        const err = await res.json();
        throw new Error(err.error || "Merge failed");
      }
      toast.success("People merged successfully");
      setMergeOpen(false);
      router.push(`/people/${mergeTarget.id}`);
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Merge failed");
    } finally {
      setMerging(false);
    }
  };

  const handleDelete = async () => {
    setDeleting(true);
    try {
      const res = await fetch(`/api/people/${id}`, { method: "DELETE" });
      if (!res.ok) throw new Error();
      toast.success("Person deleted");
      setDeleteOpen(false);
      router.push("/people");
    } catch {
      toast.error("Failed to delete person");
    } finally {
      setDeleting(false);
    }
  };

  if (loading) {
    return (
      <div className="space-y-6">
        <Skeleton className="h-8 w-24 rounded-xl" />
        <Skeleton className="h-10 w-64 rounded-xl" />
        <div className="grid gap-6 lg:grid-cols-2">
          <Skeleton className="h-80 rounded-2xl" />
          <Skeleton className="h-80 rounded-2xl" />
        </div>
      </div>
    );
  }

  if (notFound || !person) {
    return (
      <div className="space-y-6">
        <Header title="Person Not Found" icon={User} />
        <p className="text-sm text-muted-foreground">
          The person you&apos;re looking for doesn&apos;t exist or has been
          removed.
        </p>
        <Button
          variant="outline"
          className="rounded-xl"
          onClick={() => router.push("/people")}
        >
          <ArrowLeft className="mr-1 size-4" /> Back to People
        </Button>
      </div>
    );
  }

  const fieldDataEntries = person.fieldData
    ? Object.entries(person.fieldData).filter(
        ([, v]) => v !== null && v !== undefined && v !== ""
      )
    : [];

  return (
    <div className="space-y-6">
      <Button
        variant="ghost"
        size="sm"
        className="w-fit rounded-xl"
        onClick={() => router.push("/people")}
      >
        <ArrowLeft className="mr-1 size-4" /> Back to People
      </Button>

      <Header
        title={`${person.firstName} ${person.lastName}`}
        description="Contact Details"
        icon={User}
      >
        <div className="flex flex-wrap gap-2">
          <Button
            variant="outline"
            size="sm"
            className="rounded-xl"
            onClick={() => setMergeOpen(true)}
          >
            <Merge className="mr-1 size-4" /> Merge with...
          </Button>
          <Button
            variant="destructive"
            size="sm"
            className="rounded-xl"
            onClick={() => setDeleteOpen(true)}
          >
            <Trash2 className="mr-1 size-4" /> Delete Person
          </Button>
        </div>
      </Header>

      <div className="grid gap-6 lg:grid-cols-2">
        {/* Contact info card */}
        <Card variant="glass">
          <CardHeader>
            <CardTitle className="flex items-center justify-between text-base">
              <span className="flex items-center gap-2">
                <User className="size-4 text-primary" />
                Contact Information
              </span>
              {!editing ? (
                <Button
                  variant="ghost"
                  size="icon-xs"
                  onClick={startEditing}
                >
                  <Edit2 className="size-3.5" />
                </Button>
              ) : (
                <div className="flex gap-1">
                  <Button
                    variant="ghost"
                    size="icon-xs"
                    onClick={cancelEditing}
                    disabled={saving}
                  >
                    <X className="size-3.5" />
                  </Button>
                  <Button
                    variant="ghost"
                    size="icon-xs"
                    onClick={handleSave}
                    disabled={saving}
                  >
                    {saving ? (
                      <Loader2 className="size-3.5 animate-spin" />
                    ) : (
                      <Save className="size-3.5" />
                    )}
                  </Button>
                </div>
              )}
            </CardTitle>
          </CardHeader>
          <CardContent className="space-y-4">
            {editing ? (
              <div className="grid gap-4 sm:grid-cols-2">
                <div>
                  <Label className="mb-1.5 block text-xs font-medium text-muted-foreground">
                    First Name
                  </Label>
                  <Input
                    value={editFields.firstName}
                    onChange={(e) =>
                      setEditFields((f) => ({
                        ...f,
                        firstName: e.target.value,
                      }))
                    }
                  />
                </div>
                <div>
                  <Label className="mb-1.5 block text-xs font-medium text-muted-foreground">
                    Last Name
                  </Label>
                  <Input
                    value={editFields.lastName}
                    onChange={(e) =>
                      setEditFields((f) => ({
                        ...f,
                        lastName: e.target.value,
                      }))
                    }
                  />
                </div>
                <div>
                  <Label className="mb-1.5 block text-xs font-medium text-muted-foreground">
                    Email
                  </Label>
                  <Input
                    type="email"
                    value={editFields.email}
                    onChange={(e) =>
                      setEditFields((f) => ({ ...f, email: e.target.value }))
                    }
                  />
                </div>
                <div>
                  <Label className="mb-1.5 block text-xs font-medium text-muted-foreground">
                    Cell Phone
                  </Label>
                  <Input
                    value={editFields.cellPhone}
                    onChange={(e) =>
                      setEditFields((f) => ({
                        ...f,
                        cellPhone: e.target.value,
                      }))
                    }
                  />
                </div>
              </div>
            ) : (
              <div className="grid gap-4 sm:grid-cols-2">
                <InfoRow label="First Name" value={person.firstName} />
                <InfoRow label="Last Name" value={person.lastName} />
                <InfoRow label="Email" value={person.email} />
                <InfoRow label="Cell Phone" value={person.cellPhone} />
              </div>
            )}

            {fieldDataEntries.length > 0 && (
              <>
                <Separator className="opacity-50" />
                <div className="space-y-3">
                  <p className="text-xs font-medium text-muted-foreground">
                    Additional Data
                  </p>
                  <div className="grid gap-3 sm:grid-cols-2">
                    {fieldDataEntries.map(([key, value]) => (
                      <InfoRow
                        key={key}
                        label={key
                          .replace(/([A-Z])/g, " $1")
                          .replace(/^./, (s) => s.toUpperCase())
                          .trim()}
                        value={String(value)}
                      />
                    ))}
                  </div>
                </div>
              </>
            )}

            <Separator className="opacity-50" />
            <div className="flex gap-4 text-xs text-muted-foreground">
              <span>Created {formatDate(person.createdAt)}</span>
              <span>Updated {formatDate(person.updatedAt)}</span>
            </div>
          </CardContent>
        </Card>

        {/* Linked cards */}
        <Card variant="glass">
          <CardHeader>
            <CardTitle className="flex items-center gap-2 text-base">
              <FileText className="size-4 text-primary" />
              Linked Response Cards
              <Badge variant="secondary" className="ml-1">
                {person._count.cards}
              </Badge>
            </CardTitle>
          </CardHeader>
          <CardContent>
            {person.cards.length === 0 ? (
              <div className="flex flex-col items-center justify-center py-8 text-center">
                <FileText className="mb-3 size-10 text-muted-foreground/30" />
                <p className="text-sm font-medium">No linked cards</p>
                <p className="mt-0.5 text-xs text-muted-foreground">
                  Cards will appear here when linked to this person
                </p>
              </div>
            ) : (
              <div className="space-y-2">
                {person.cards.map((card) => (
                  <button
                    key={card.id}
                    className="flex w-full items-center justify-between gap-3 rounded-xl border border-border/50 bg-muted/20 px-3 py-2.5 text-left transition-colors hover:bg-muted/40"
                    onClick={() => router.push(`/cards/${card.id}`)}
                  >
                    <div className="min-w-0 flex-1">
                      <p className="truncate text-sm font-medium">
                        {card.name || "Unnamed Card"}
                      </p>
                      <p className="mt-0.5 text-xs text-muted-foreground">
                        {formatDate(card.createdAt)}
                      </p>
                    </div>
                    <div className="flex shrink-0 gap-1.5">
                      <Badge
                        variant="secondary"
                        className={cn(
                          "text-[10px] capitalize",
                          card.ocrStatus === "complete" &&
                            "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
                          card.ocrStatus === "error" &&
                            "bg-red-500/10 text-red-700 dark:text-red-300",
                          card.ocrStatus === "processing" &&
                            "bg-primary/10 text-primary"
                        )}
                      >
                        {card.ocrStatus}
                      </Badge>
                      <Badge
                        variant="secondary"
                        className={cn(
                          "text-[10px] capitalize",
                          card.reviewStatus === "reviewed" &&
                            "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
                          card.reviewStatus === "unreviewed" &&
                            "bg-amber-500/10 text-amber-700 dark:text-amber-300"
                        )}
                      >
                        {card.reviewStatus}
                      </Badge>
                    </div>
                  </button>
                ))}
              </div>
            )}
          </CardContent>
        </Card>
      </div>

      {/* Merge dialog */}
      <Dialog open={mergeOpen} onOpenChange={setMergeOpen}>
        <DialogContent className="sm:max-w-md">
          <DialogHeader>
            <DialogTitle>Merge Person</DialogTitle>
            <DialogDescription>
              Search for another person to merge{" "}
              <strong>
                {person.firstName} {person.lastName}
              </strong>{" "}
              into. Cards and data will be moved to the target person.
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-3">
            <div className="relative">
              <Search className="absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
              <Input
                placeholder="Search people..."
                value={mergeSearch}
                onChange={(e) => {
                  setMergeSearch(e.target.value);
                  setMergeTarget(null);
                }}
                className="pl-9"
              />
            </div>

            {mergeSearching && (
              <div className="flex items-center justify-center py-4">
                <Loader2 className="size-5 animate-spin text-muted-foreground" />
              </div>
            )}

            {!mergeSearching && mergeResults.length > 0 && (
              <div className="max-h-48 space-y-1 overflow-y-auto">
                {mergeResults.map((p) => (
                  <button
                    key={p.id}
                    className={cn(
                      "flex w-full items-center justify-between rounded-lg px-3 py-2 text-left text-sm transition-colors",
                      mergeTarget?.id === p.id
                        ? "bg-primary/10 text-primary ring-1 ring-primary/30"
                        : "hover:bg-muted/60"
                    )}
                    onClick={() => setMergeTarget(p)}
                  >
                    <div>
                      <span className="font-medium">
                        {p.firstName} {p.lastName}
                      </span>
                      {p.email && (
                        <span className="ml-2 text-xs text-muted-foreground">
                          {p.email}
                        </span>
                      )}
                    </div>
                    <Badge variant="secondary" className="text-[10px]">
                      {p._count.cards} cards
                    </Badge>
                  </button>
                ))}
              </div>
            )}

            {!mergeSearching &&
              mergeSearch.trim() &&
              mergeResults.length === 0 && (
                <p className="py-4 text-center text-sm text-muted-foreground">
                  No matching people found
                </p>
              )}
          </div>

          <DialogFooter>
            <Button
              variant="outline"
              size="sm"
              onClick={() => setMergeOpen(false)}
            >
              Cancel
            </Button>
            <Button
              size="sm"
              disabled={!mergeTarget || merging}
              onClick={handleMerge}
            >
              {merging ? (
                <>
                  <Loader2 className="mr-1 size-4 animate-spin" /> Merging...
                </>
              ) : (
                <>
                  <Merge className="mr-1 size-4" /> Merge into{" "}
                  {mergeTarget
                    ? `${mergeTarget.firstName} ${mergeTarget.lastName}`
                    : "..."}
                </>
              )}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Delete confirmation dialog */}
      <Dialog open={deleteOpen} onOpenChange={setDeleteOpen}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Delete Person</DialogTitle>
            <DialogDescription>
              Are you sure you want to delete{" "}
              <strong>
                {person.firstName} {person.lastName}
              </strong>
              ? Their linked cards will be unlinked but not deleted.
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button
              variant="outline"
              size="sm"
              onClick={() => setDeleteOpen(false)}
            >
              Cancel
            </Button>
            <Button
              variant="destructive"
              size="sm"
              disabled={deleting}
              onClick={handleDelete}
            >
              {deleting ? (
                <>
                  <Loader2 className="mr-1 size-4 animate-spin" /> Deleting...
                </>
              ) : (
                <>
                  <Trash2 className="mr-1 size-4" /> Delete
                </>
              )}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}

function InfoRow({
  label,
  value,
}: {
  label: string;
  value: string | null | undefined;
}) {
  return (
    <div>
      <p className="text-xs font-medium text-muted-foreground">{label}</p>
      <p className="mt-0.5 text-sm">{value || "—"}</p>
    </div>
  );
}
