"use client";

import * as React from "react";
import { useParams } from "next/navigation";
import {
  ArrowDown,
  ArrowUp,
  ArrowUpDown,
  ChevronDown,
  ChevronRight,
  ListTodo,
  Plus,
} from "lucide-react";

import { Badge } from "@/components/ui/badge";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";
import {
  TooltipProvider,
} from "@/components/ui/tooltip";
import type { ViewConfig, ViewObject, ViewSort } from "@/lib/hooks/use-view-data";
import { useViewData } from "@/lib/hooks/use-view-data";
import { api } from "@/lib/trpc";
import { cn } from "@/lib/utils";

import {
  getDueDateValue,
  getPriorityValue,
  ListItem,
  LIST_ROW_GRID,
} from "./list-item";

type SortField = "status" | "title" | "assignees" | "priority" | "dueDate";

function groupByField(
  objects: ViewObject[],
  groupBy: string,
): Record<string, ViewObject[]> {
  const groups: Record<string, ViewObject[]> = {};
  for (const obj of objects) {
    const key = String(
      (obj as unknown as Record<string, unknown>)[groupBy] ?? "No Value",
    );
    if (!groups[key]) groups[key] = [];
    groups[key].push(obj);
  }
  return groups;
}

function rankPriority(p: string): number {
  const order = ["High", "Medium", "Low"];
  const i = order.indexOf(p);
  return i === -1 ? 999 : i;
}

function firstAssigneeName(o: ViewObject): string {
  return o.assignees?.[0]?.user?.name ?? "";
}

function compareDue(a: string, b: string): number {
  if (a === "—" && b === "—") return 0;
  if (a === "—") return 1;
  if (b === "—") return -1;
  const ta = new Date(a).getTime();
  const tb = new Date(b).getTime();
  if (Number.isNaN(ta) || Number.isNaN(tb)) return a.localeCompare(b);
  return ta - tb;
}

function sortItemsByField(items: ViewObject[], sort: ViewSort): ViewObject[] {
  const dir = sort.direction === "asc" ? 1 : -1;
  const copy = [...items];
  copy.sort((a, b) => {
    let cmp = 0;
    switch (sort.field) {
      case "priority": {
        const pa = getPriorityValue(a);
        const pb = getPriorityValue(b);
        cmp = rankPriority(pa) - rankPriority(pb);
        if (cmp === 0) cmp = pa.localeCompare(pb);
        break;
      }
      case "dueDate":
        cmp = compareDue(getDueDateValue(a), getDueDateValue(b));
        break;
      case "assignees":
        cmp = firstAssigneeName(a).localeCompare(firstAssigneeName(b));
        break;
      case "title":
        cmp = a.title.localeCompare(b.title);
        break;
      case "status":
        cmp = String(a.status ?? "").localeCompare(String(b.status ?? ""));
        break;
      default:
        cmp = 0;
    }
    return cmp * dir;
  });
  return copy;
}

function refineSort(items: ViewObject[], sorts: ViewSort[]): ViewObject[] {
  if (sorts.length === 0) return items;
  const s = sorts[0];
  if (s.field === "title" || s.field === "status") {
    return items;
  }
  return sortItemsByField(items, s);
}

function nextSort(field: SortField, sorts: ViewSort[]): ViewSort[] {
  const first = sorts[0];
  if (first?.field === field) {
    return [{ field, direction: first.direction === "asc" ? "desc" : "asc" }];
  }
  return [{ field, direction: "asc" }];
}

function SortHeaderButton({
  label,
  field,
  sorts,
  onSort,
}: {
  label: string;
  field: SortField;
  sorts: ViewSort[];
  onSort: (field: SortField) => void;
}) {
  const active = sorts[0]?.field === field;
  const dir = active ? sorts[0].direction : null;
  return (
    <button
      type="button"
      onClick={() => onSort(field)}
      className={cn(
        "inline-flex items-center gap-1 truncate text-left text-xs font-medium uppercase tracking-wide text-muted-foreground transition-colors hover:text-foreground",
        active && "text-foreground",
      )}
    >
      <span className="truncate">{label}</span>
      {active ? (
        dir === "asc" ? (
          <ArrowUp className="h-3 w-3 shrink-0 opacity-80" />
        ) : (
          <ArrowDown className="h-3 w-3 shrink-0 opacity-80" />
        )
      ) : (
        <ArrowUpDown className="h-3 w-3 shrink-0 opacity-40" />
      )}
    </button>
  );
}

function ListSkeleton() {
  return (
    <div className="flex flex-col">
      {Array.from({ length: 8 }).map((_, i) => (
        <div
          key={i}
          className={cn(
            LIST_ROW_GRID,
            "h-9 border-b border-border/40",
            i % 2 === 1 && "bg-muted/15",
          )}
        >
          <div className="flex justify-center">
            <div className="h-3.5 w-3.5 animate-pulse rounded bg-muted" />
          </div>
          <div className="flex justify-center">
            <div className="h-2.5 w-2.5 animate-pulse rounded-full bg-muted" />
          </div>
          <div className="h-3 animate-pulse rounded bg-muted/80" />
          <div className="flex gap-1">
            <div className="h-6 w-6 animate-pulse rounded-full bg-muted" />
          </div>
          <div className="h-5 w-14 animate-pulse rounded-full bg-muted" />
          <div className="h-3 w-16 animate-pulse rounded bg-muted/80" />
          <div />
        </div>
      ))}
    </div>
  );
}

function EmptyState() {
  return (
    <div className="flex flex-col items-center justify-center gap-4 px-6 py-20 text-center">
      <div className="flex h-20 w-20 items-center justify-center rounded-2xl border border-dashed border-border bg-muted/30">
        <ListTodo className="h-10 w-10 text-muted-foreground/70" strokeWidth={1.25} />
      </div>
      <div className="space-y-1">
        <p className="text-sm font-medium text-foreground">No items yet</p>
        <p className="max-w-sm text-xs text-muted-foreground">
          Create a task or adjust filters to see work here.
        </p>
      </div>
    </div>
  );
}

export interface ListViewProps {
  config: ViewConfig;
}

export function ListView({ config }: ListViewProps) {
  const params = useParams();
  const workspaceId =
    typeof params?.workspaceSlug === "string" ? params.workspaceSlug : undefined;
  const parentId =
    typeof params?.projectId === "string" ? params.projectId : undefined;

  const [sorts, setSorts] = React.useState<ViewSort[]>(config.sorts);
  React.useEffect(() => {
    setSorts(config.sorts);
  }, [config.sorts]);

  const effectiveConfig = React.useMemo(
    () => ({ ...config, sorts }),
    [config, sorts],
  );

  const { items, isLoading, total } = useViewData(
    effectiveConfig,
    workspaceId,
    parentId,
  );

  const displayItems = React.useMemo(
    () => refineSort(items, sorts),
    [items, sorts],
  );

  const displayGrouped = React.useMemo(() => {
    if (!config.groupBy) return null;
    return groupByField(displayItems, config.groupBy);
  }, [displayItems, config.groupBy]);

  const [selected, setSelected] = React.useState<Set<string>>(new Set());
  const toggleSelect = React.useCallback((id: string) => {
    setSelected((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  }, []);

  const [collapsed, setCollapsed] = React.useState<Record<string, boolean>>({});
  const toggleGroup = React.useCallback((key: string) => {
    setCollapsed((c) => ({ ...c, [key]: !c[key] }));
  }, []);

  const [isCreating, setIsCreating] = React.useState(false);
  const [newTitle, setNewTitle] = React.useState("");
  const utils = api.useUtils();
  const createObject = api.objects.create.useMutation({
    onSuccess: () => {
      utils.objects.list.invalidate();
      setNewTitle("");
      setIsCreating(false);
    },
  });

  const onHeaderSort = React.useCallback((field: SortField) => {
    setSorts((s) => nextSort(field, s));
  }, []);

  const isGrouped = Boolean(config.groupBy);

  const headerRow = (
    <div
      className={cn(
        LIST_ROW_GRID,
        "sticky top-0 z-10 h-9 shrink-0 border-b border-border bg-background/95 py-1 backdrop-blur supports-[backdrop-filter]:bg-background/80",
      )}
    >
      <div />
      <SortHeaderButton
        label="Status"
        field="status"
        sorts={sorts}
        onSort={onHeaderSort}
      />
      <SortHeaderButton
        label="Title"
        field="title"
        sorts={sorts}
        onSort={onHeaderSort}
      />
      <SortHeaderButton
        label="Assignees"
        field="assignees"
        sorts={sorts}
        onSort={onHeaderSort}
      />
      <SortHeaderButton
        label="Priority"
        field="priority"
        sorts={sorts}
        onSort={onHeaderSort}
      />
      <SortHeaderButton
        label="Due date"
        field="dueDate"
        sorts={sorts}
        onSort={onHeaderSort}
      />
      <div />
    </div>
  );

  let body: React.ReactNode = null;

  if (isLoading) {
    body = <ListSkeleton />;
  } else if (total === 0) {
    body = <EmptyState />;
  } else if (isGrouped && displayGrouped) {
    const keys = Object.keys(displayGrouped).sort((a, b) =>
      a.localeCompare(b, undefined, { sensitivity: "base" }),
    );
    body = (
      <div className="flex flex-col">
        {keys.map((groupKey, gi) => {
          const groupItems = displayGrouped[groupKey] ?? [];
          const expanded = !collapsed[groupKey];
          return (
            <div key={groupKey} className="border-b border-border/50">
              <button
                type="button"
                onClick={() => toggleGroup(groupKey)}
                className="flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-accent/40"
              >
                {expanded ? (
                  <ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground" />
                ) : (
                  <ChevronRight className="h-4 w-4 shrink-0 text-muted-foreground" />
                )}
                <span className="text-sm font-semibold text-foreground">
                  {groupKey}
                </span>
                <Badge variant="secondary" className="h-5 px-1.5 text-[10px] font-semibold">
                  {groupItems.length}
                </Badge>
              </button>
              {expanded && (
                <div>
                  {groupItems.map((obj, i) => (
                    <ListItem
                      key={obj.id}
                      object={obj}
                      onSelect={toggleSelect}
                      selected={selected.has(obj.id)}
                      rowIndex={i + gi}
                    />
                  ))}
                </div>
              )}
            </div>
          );
        })}
      </div>
    );
  } else {
    body = (
      <div className="flex flex-col">
        {displayItems.map((obj, i) => (
          <ListItem
            key={obj.id}
            object={obj}
            onSelect={toggleSelect}
            selected={selected.has(obj.id)}
            rowIndex={i}
          />
        ))}
      </div>
    );
  }

  return (
    <TooltipProvider delayDuration={300}>
      <div className="flex h-full min-h-0 flex-col rounded-md border border-border bg-card text-card-foreground shadow-sm">
        {headerRow}
        <Separator />
        <ScrollArea className="min-h-0 flex-1">
          <div className="pb-2">
            {body}
            {!isLoading && (
              <>
                {isCreating ? (
                  <div className="flex items-center gap-2 border-t border-border px-4 py-2">
                    <input
                      autoFocus
                      className="flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
                      placeholder="Task title…"
                      value={newTitle}
                      onChange={(e) => setNewTitle(e.target.value)}
                      onKeyDown={(e) => {
                        if (e.key === "Enter" && newTitle.trim() && workspaceId) {
                          e.preventDefault();
                          createObject.mutate({
                            type: "task",
                            title: newTitle.trim(),
                            workspaceId,
                            parentId: parentId ?? undefined,
                          });
                        }
                        if (e.key === "Escape") {
                          setIsCreating(false);
                          setNewTitle("");
                        }
                      }}
                      onBlur={() => {
                        if (createObject.isPending) return;
                        if (newTitle.trim() && workspaceId) {
                          createObject.mutate({
                            type: "task",
                            title: newTitle.trim(),
                            workspaceId,
                            parentId: parentId ?? undefined,
                          });
                        } else {
                          setIsCreating(false);
                        }
                      }}
                    />
                  </div>
                ) : (
                  <button
                    type="button"
                    className="flex w-full items-center gap-2 border-t border-border px-4 py-2 text-sm text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground"
                    onClick={() => setIsCreating(true)}
                  >
                    <Plus className="size-4 shrink-0" />
                    Add task
                  </button>
                )}
              </>
            )}
          </div>
        </ScrollArea>
      </div>
    </TooltipProvider>
  );
}
