"use client";

import * as React from "react";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@radix-ui/react-tabs";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  Check,
  CheckSquare,
  ChevronDown,
  ExternalLink,
  FileText,
  Folder,
  Link2,
  Plus,
  X,
} from "lucide-react";

import { cn } from "@/lib/utils";
import { api } from "@/lib/trpc";
import {
  usePanelStore,
  type PanelDetailTab,
} from "@/lib/stores/panel-store";
import { AssigneePicker, WORKSPACE_USERS } from "@/components/panels/assignee-picker";
import {
  PropertyEditor,
  type PropertyFieldType,
} from "@/components/panels/property-editor";
import {
  Avatar,
  AvatarFallback,
  AvatarImage,
} from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";

const OBJECT_DETAIL_KEY = "object-detail";

type StatusValue = "open" | "in_progress" | "done" | "closed";

const STATUS_OPTIONS: {
  value: StatusValue;
  label: string;
  dot: string;
}[] = [
  { value: "open", label: "Open", dot: "bg-slate-400" },
  { value: "in_progress", label: "In progress", dot: "bg-amber-500" },
  { value: "done", label: "Done", dot: "bg-emerald-500" },
  { value: "closed", label: "Closed", dot: "bg-zinc-400" },
];

const MOCK_OBJECT: ObjectDetailData = {
  id: "demo",
  title: "Design Landing Page",
  type: "task",
  status: "in_progress",
  description: "Create wireframes and align with brand guidelines before handoff.",
  assignees: [
    { user: { id: "u1", name: "Alice", avatarUrl: null } },
  ],
  propertyValues: [
    {
      id: "pv1",
      propertyDefinition: {
        name: "Priority",
        fieldType: "select",
        config: {
          options: [
            { label: "High", value: "High" },
            { label: "Medium", value: "Medium" },
            { label: "Low", value: "Low" },
          ],
        },
      },
      value: "High",
    },
    {
      id: "pv2",
      propertyDefinition: {
        name: "Due Date",
        fieldType: "date",
        config: {},
      },
      value: "2025-04-01",
    },
  ],
  children: [
    { id: "child-1", title: "Review copy", type: "task" },
  ],
  relations: [
    { id: "rel-1", title: "Brand guidelines PDF", type: "document" },
    { id: "rel-2", title: "Q2 marketing plan", type: "task" },
  ],
};

export interface ObjectDetailData {
  id: string;
  title: string;
  type: string;
  status: string;
  description: string | null;
  assignees: {
    user: { id?: string; name: string; avatarUrl?: string | null };
  }[];
  propertyValues: {
    id?: string;
    propertyDefinition: {
      name: string;
      fieldType: string;
      config?: Record<string, unknown> | null;
    };
    value: unknown;
  }[];
  children?: { id: string; title: string; type: string }[];
  relations?: { id: string; title: string; type: string }[];
}

function normalizeFieldType(raw: string): PropertyFieldType {
  const t = raw.toLowerCase().replace(/[\s-]+/g, "_") as PropertyFieldType;
  const allowed: PropertyFieldType[] = [
    "text",
    "richtext",
    "number",
    "date",
    "select",
    "multiselect",
    "person",
    "relation",
    "url",
    "file",
    "checkbox",
  ];
  return allowed.includes(t) ? t : "text";
}

function typeLabel(type: string) {
  const t = type.toLowerCase();
  if (t === "task") return "Task";
  if (t === "document") return "Document";
  return type.charAt(0).toUpperCase() + type.slice(1);
}

function TypeIcon({ type }: { type: string }) {
  const t = type.toLowerCase();
  if (t === "document") return <FileText className="size-4 text-teal-600 dark:text-teal-400" />;
  if (t === "task") return <CheckSquare className="size-4 text-violet-600 dark:text-violet-400" />;
  return <Folder className="size-4 text-muted-foreground" />;
}

function initials(name: string) {
  return name
    .split(/\s+/)
    .map((p) => p[0])
    .join("")
    .slice(0, 2)
    .toUpperCase();
}

function useObjectDetailQuery(objectId: string | null) {
  const utils = api.useUtils();
  return useQuery({
    queryKey: [OBJECT_DETAIL_KEY, objectId],
    queryFn: async (): Promise<ObjectDetailData | null> => {
      if (!objectId) return null;
      const fetcher = (
        utils as unknown as {
          objects?: { getById?: { fetch: (args: { id: string }) => Promise<ObjectDetailData> } };
        }
      ).objects?.getById?.fetch;
      if (typeof fetcher === "function") {
        return fetcher({ id: objectId });
      }
      await new Promise((r) => setTimeout(r, 220));
      return { ...MOCK_OBJECT, id: objectId };
    },
    enabled: Boolean(objectId),
  });
}

function DetailSkeleton() {
  return (
    <div className="flex animate-pulse flex-col gap-3 p-3">
      <div className="flex gap-2">
        <div className="size-8 rounded-md bg-muted" />
        <div className="flex flex-1 flex-col gap-2">
          <div className="h-3 w-20 rounded bg-muted" />
          <div className="h-6 w-full rounded bg-muted" />
        </div>
      </div>
      <div className="h-9 w-full rounded-md bg-muted" />
      <div className="h-24 w-full rounded-md bg-muted" />
      <div className="h-32 w-full rounded-md bg-muted" />
    </div>
  );
}

export function ObjectDetail() {
  const objectId = usePanelStore((s) => s.objectId);
  const activeTab = usePanelStore((s) => s.activeTab);
  const setActiveTab = usePanelStore((s) => s.setActiveTab);
  const closePanel = usePanelStore((s) => s.close);
  const openPanel = usePanelStore((s) => s.open);

  const queryClient = useQueryClient();
  const utils = api.useUtils();

  const { data, isPending, isError, error } = useObjectDetailQuery(objectId);

  const [titleDraft, setTitleDraft] = React.useState("");
  const [editingTitle, setEditingTitle] = React.useState(false);
  const [descriptionDraft, setDescriptionDraft] = React.useState("");
  const [assigneeOpen, setAssigneeOpen] = React.useState(false);

  React.useEffect(() => {
    if (data?.title != null) setTitleDraft(data.title);
  }, [data?.title]);

  React.useEffect(() => {
    if (data?.description != null) setDescriptionDraft(data.description ?? "");
  }, [data?.description]);

  const mergeObjectCache = React.useCallback(
    (id: string, patch: Partial<ObjectDetailData>) => {
      queryClient.setQueryData<ObjectDetailData | null>(
        [OBJECT_DETAIL_KEY, id],
        (old) => (old ? { ...old, ...patch } : old),
      );
    },
    [queryClient],
  );

  const updateObject = useMutation({
    mutationFn: async (patch: Partial<ObjectDetailData> & { id: string }) => {
      const u = utils as unknown as {
        objects?: { update?: { mutate: (args: unknown) => Promise<unknown> } };
      };
      if (typeof u.objects?.update?.mutate === "function") {
        return u.objects.update.mutate(patch);
      }
    },
    onMutate: async (patch) => {
      mergeObjectCache(patch.id, patch);
    },
  });

  const setPropertyValue = useMutation({
    mutationFn: async (args: {
      objectId: string;
      propertyValueId?: string;
      propertyDefinitionId?: string;
      value: unknown;
    }) => {
      const u = utils as unknown as {
        properties?: { setValue?: { mutate: (a: unknown) => Promise<unknown> } };
      };
      if (typeof u.properties?.setValue?.mutate === "function") {
        return u.properties.setValue.mutate(args);
      }
    },
  });

  const handlePropertyChange = (
    index: number,
    next: unknown,
    row: ObjectDetailData["propertyValues"][number],
  ) => {
    if (!data) return;
    const nextRows = [...data.propertyValues];
    nextRows[index] = { ...row, value: next };
    mergeObjectCache(data.id, { propertyValues: nextRows });
    setPropertyValue.mutate({
      objectId: data.id,
      propertyValueId: row.id,
      value: next,
    });
  };

  const assignedIds = React.useMemo(() => {
    if (!data) return [];
    return data.assignees
      .map((a) => a.user.id)
      .filter((id): id is string => Boolean(id));
  }, [data]);

  const toggleAssignee = (userId: string) => {
    if (!data) return;
    const user = WORKSPACE_USERS.find((u) => u.id === userId);
    if (!user) return;
    const has = assignedIds.includes(userId);
    let nextAssignees: ObjectDetailData["assignees"];
    if (has) {
      nextAssignees = data.assignees.filter((a) => a.user.id !== userId);
    } else {
      nextAssignees = [
        ...data.assignees,
        { user: { id: user.id, name: user.name, avatarUrl: user.avatarUrl } },
      ];
    }
    mergeObjectCache(data.id, { assignees: nextAssignees });
    const u = utils as unknown as {
      objects?: { assign?: { mutate: (a: unknown) => Promise<unknown> } };
    };
    if (typeof u.objects?.assign?.mutate === "function") {
      u.objects.assign.mutate({
        objectId: data.id,
        userId,
        assign: !has,
      });
    }
  };

  const commitTitle = () => {
    if (!data || titleDraft.trim() === data.title) {
      setEditingTitle(false);
      return;
    }
    updateObject.mutate({ id: data.id, title: titleDraft.trim() });
    setEditingTitle(false);
  };

  const commitDescription = () => {
    if (!data) return;
    if (descriptionDraft === (data.description ?? "")) return;
    updateObject.mutate({ id: data.id, description: descriptionDraft });
  };

  const setStatus = (status: StatusValue) => {
    if (!data) return;
    updateObject.mutate({ id: data.id, status });
  };

  const onTabChange = (v: string) => {
    setActiveTab(v as PanelDetailTab);
  };

  if (!objectId) {
    return (
      <div className="flex flex-1 flex-col items-center justify-center gap-2 p-6 text-center text-xs text-muted-foreground">
        <p>No object selected.</p>
        <Button variant="outline" size="sm" onClick={() => closePanel()}>
          Close panel
        </Button>
      </div>
    );
  }

  if (isPending) {
    return <DetailSkeleton />;
  }

  if (isError || !data) {
    return (
      <div className="p-4 text-xs text-destructive">
        {isError
          ? error instanceof Error
            ? error.message
            : "Failed to load object."
          : "Nothing to display."}
      </div>
    );
  }

  const status =
    STATUS_OPTIONS.find((s) => s.value === data.status)?.value ??
    (data.status as StatusValue);
  const statusMeta =
    STATUS_OPTIONS.find((s) => s.value === status) ?? STATUS_OPTIONS[0];

  return (
    <div className="flex h-full min-h-0 flex-1 flex-col bg-card">
      <header className="shrink-0 border-b border-border px-3 pb-2 pt-3">
        <div className="flex items-start gap-2">
          <div className="mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-md border border-border bg-muted/40">
            <TypeIcon type={data.type} />
          </div>
          <div className="min-w-0 flex-1">
            <div className="mb-1 flex items-center gap-2">
              <Badge
                variant="secondary"
                className="h-5 px-1.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground"
              >
                {typeLabel(data.type)}
              </Badge>
            </div>
            {editingTitle ? (
              <Input
                autoFocus
                value={titleDraft}
                onChange={(e) => setTitleDraft(e.target.value)}
                onBlur={commitTitle}
                onKeyDown={(e) => {
                  if (e.key === "Enter") {
                    e.preventDefault();
                    commitTitle();
                  }
                  if (e.key === "Escape") {
                    setTitleDraft(data.title);
                    setEditingTitle(false);
                  }
                }}
                className="h-8 text-sm font-semibold"
              />
            ) : (
              <button
                type="button"
                onClick={() => setEditingTitle(true)}
                className="w-full rounded px-0.5 text-left text-sm font-semibold leading-snug text-foreground hover:bg-muted/60"
              >
                {data.title}
              </button>
            )}
          </div>
          <Button
            variant="ghost"
            size="icon"
            className="size-8 shrink-0 text-muted-foreground hover:text-foreground"
            onClick={() => closePanel()}
            aria-label="Close panel"
          >
            <X className="size-4" />
          </Button>
        </div>

        <div className="mt-2 flex items-center gap-2">
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button
                variant="outline"
                size="sm"
                className="h-7 gap-1.5 border-border px-2 text-xs font-normal"
              >
                <span
                  className={cn("size-2 shrink-0 rounded-full", statusMeta.dot)}
                />
                {statusMeta.label}
                <ChevronDown className="size-3.5 opacity-60" />
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="start" className="w-44">
              {STATUS_OPTIONS.map((opt) => (
                <DropdownMenuItem
                  key={opt.value}
                  className="gap-2 text-xs"
                  onClick={() => setStatus(opt.value)}
                >
                  <span className={cn("size-2 rounded-full", opt.dot)} />
                  {opt.label}
                  {opt.value === status ? (
                    <Check className="ml-auto size-3.5 text-primary" />
                  ) : null}
                </DropdownMenuItem>
              ))}
            </DropdownMenuContent>
          </DropdownMenu>
        </div>
      </header>

      <Tabs
        value={activeTab}
        onValueChange={onTabChange}
        className="flex min-h-0 flex-1 flex-col"
      >
        <TabsList className="flex shrink-0 gap-0 border-b border-border px-1">
          {(
            [
              ["details", "Details"],
              ["activity", "Activity"],
              ["comments", "Comments"],
            ] as const
          ).map(([value, label]) => (
            <TabsTrigger
              key={value}
              value={value}
              className={cn(
                "relative flex-1 px-2 py-2 text-center text-[11px] font-semibold uppercase tracking-wide text-muted-foreground transition-colors",
                "hover:text-foreground",
                "data-[state=active]:text-foreground",
                "data-[state=active]:after:absolute data-[state=active]:after:inset-x-2 data-[state=active]:after:bottom-0 data-[state=active]:after:h-0.5 data-[state=active]:after:rounded-full data-[state=active]:after:bg-primary",
              )}
            >
              {label}
            </TabsTrigger>
          ))}
        </TabsList>

        <TabsContent
          value="details"
          className="flex min-h-0 flex-1 flex-col overflow-hidden animate-in fade-in-0 duration-200 ease-out data-[state=inactive]:hidden"
        >
          <ScrollArea className="min-h-0 flex-1">
            <div className="flex flex-col gap-0 px-3 pb-6 pt-2">
              <section className="py-2">
                <h3 className="mb-2 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
                  Assignees
                </h3>
                <div className="flex flex-wrap items-center gap-1.5">
                  {data.assignees.map((a, i) => (
                    <Avatar
                      key={`${a.user.id ?? a.user.name}-${i}`}
                      className="size-7 border border-border"
                      title={a.user.name}
                    >
                      <AvatarImage src={a.user.avatarUrl ?? undefined} alt="" />
                      <AvatarFallback className="text-[10px]">
                        {initials(a.user.name)}
                      </AvatarFallback>
                    </Avatar>
                  ))}
                  <AssigneePicker
                    open={assigneeOpen}
                    onOpenChange={setAssigneeOpen}
                    assignedIds={assignedIds}
                    onToggle={toggleAssignee}
                  >
                    <Button
                      variant="outline"
                      size="sm"
                      className="h-7 gap-1 px-2 text-[11px] font-normal"
                    >
                      <Plus className="size-3.5" />
                      Add assignee
                    </Button>
                  </AssigneePicker>
                </div>
              </section>

              <Separator className="bg-border/80" />

              <section className="py-2">
                <div className="mb-2 flex items-center justify-between gap-2">
                  <h3 className="text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
                    Properties
                  </h3>
                  <Button
                    variant="ghost"
                    size="sm"
                    className="h-6 px-2 text-[10px] font-medium text-primary"
                    type="button"
                  >
                    <Plus className="mr-1 size-3" />
                    Add property
                  </Button>
                </div>
                <div className="rounded-md border border-border/80 bg-muted/20">
                  {data.propertyValues.length === 0 ? (
                    <p className="px-3 py-4 text-center text-[11px] text-muted-foreground">
                      No custom properties yet.
                    </p>
                  ) : (
                    data.propertyValues.map((row, index) => (
                      <div
                        key={row.id ?? `${row.propertyDefinition.name}-${index}`}
                        className="border-b border-border/60 px-2 last:border-b-0"
                      >
                        <PropertyEditor
                          definition={{
                            name: row.propertyDefinition.name,
                            fieldType: normalizeFieldType(
                              row.propertyDefinition.fieldType,
                            ),
                            config: row.propertyDefinition.config as
                              | { options?: { label: string; value: string }[] }
                              | undefined,
                          }}
                          value={row.value}
                          onChange={(v) => handlePropertyChange(index, v, row)}
                        />
                      </div>
                    ))
                  )}
                </div>
              </section>

              <Separator className="bg-border/80" />

              <section className="py-2">
                <h3 className="mb-2 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
                  Description
                </h3>
                <textarea
                  value={descriptionDraft}
                  onChange={(e) => setDescriptionDraft(e.target.value)}
                  onBlur={commitDescription}
                  rows={4}
                  placeholder="Add a description…"
                  className="w-full resize-y rounded-md border border-input bg-background px-2 py-1.5 text-xs leading-relaxed ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1"
                />
              </section>

              {data.children && data.children.length > 0 ? (
                <>
                  <Separator className="bg-border/80" />
                  <section className="py-2">
                    <h3 className="mb-2 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
                      Subtasks
                    </h3>
                    <ul className="space-y-1">
                      {data.children.map((c) => (
                        <li key={c.id}>
                          <button
                            type="button"
                            onClick={() => openPanel("object-detail", c.id)}
                            className="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs transition-colors hover:bg-muted/70"
                          >
                            <CheckSquare className="size-3.5 shrink-0 text-violet-500" />
                            <span className="min-w-0 flex-1 truncate font-medium">
                              {c.title}
                            </span>
                            <Badge
                              variant="outline"
                              className="h-5 shrink-0 px-1.5 text-[9px] font-normal uppercase"
                            >
                              {typeLabel(c.type)}
                            </Badge>
                          </button>
                        </li>
                      ))}
                    </ul>
                  </section>
                </>
              ) : null}

              <Separator className="bg-border/80" />

              <section className="py-2">
                <div className="mb-2 flex items-center justify-between gap-2">
                  <h3 className="text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
                    Relations
                  </h3>
                  <Button
                    variant="ghost"
                    size="sm"
                    className="h-6 px-2 text-[10px] font-medium text-primary"
                    type="button"
                  >
                    <Link2 className="mr-1 size-3" />
                    Add relation
                  </Button>
                </div>
                {data.relations && data.relations.length > 0 ? (
                  <ul className="space-y-1">
                    {data.relations.map((r) => (
                      <li key={r.id}>
                        <button
                          type="button"
                          onClick={() => openPanel("object-detail", r.id)}
                          className="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs transition-colors hover:bg-muted/70"
                        >
                          <ExternalLink className="size-3.5 shrink-0 text-muted-foreground" />
                          <span className="min-w-0 flex-1 truncate">
                            {r.title}
                          </span>
                          <Badge
                            variant="secondary"
                            className="h-5 shrink-0 px-1.5 text-[9px] font-normal uppercase"
                          >
                            {typeLabel(r.type)}
                          </Badge>
                        </button>
                      </li>
                    ))}
                  </ul>
                ) : (
                  <p className="py-2 text-[11px] text-muted-foreground">
                    No relations yet.
                  </p>
                )}
              </section>
            </div>
          </ScrollArea>
        </TabsContent>

        <TabsContent
          value="activity"
          className="min-h-0 flex-1 animate-in fade-in-0 duration-200 ease-out data-[state=inactive]:hidden"
        >
          <div className="p-4 text-xs text-muted-foreground">
            <p className="rounded-md border border-dashed border-border bg-muted/20 px-3 py-6 text-center">
              Activity feed will appear here (audit log, updates, mentions).
            </p>
          </div>
        </TabsContent>

        <TabsContent
          value="comments"
          className="min-h-0 flex-1 animate-in fade-in-0 duration-200 ease-out data-[state=inactive]:hidden"
        >
          <div className="p-4 text-xs text-muted-foreground">
            <p className="rounded-md border border-dashed border-border bg-muted/20 px-3 py-6 text-center">
              Comments thread — coming soon.
            </p>
          </div>
        </TabsContent>
      </Tabs>
    </div>
  );
}
