"use client";

import { useState } from "react";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import {
  Archive,
  ChevronRight,
  ClipboardList,
  GripVertical,
  MoreVertical,
  Pencil,
  Plus,
  Sparkles,
  StickyNote,
  Trash2,
} from "lucide-react";

import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { TodoCheckbox } from "@/components/board/todo-checkbox";
import { MouseFollowTooltip } from "@/components/board/mouse-follow-tooltip";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { getBrighterColor, getComplementaryColor, getGroupColor } from "@/lib/colors";
import { isDarkTheme } from "@/components/theme/use-dark-theme";
import { useBoard } from "@/components/board/board-context";
import { useBoardView } from "@/components/board/board-view-provider";
import { useHoldOnComplete } from "@/components/hold-on-complete";
import { NotesDialog } from "@/components/board/notes-dialog";
import { TodoAiDialog } from "@/components/board/todo-ai-dialog";
import { TodoCreateDialog } from "@/components/board/todo-create-dialog";
import { TodoCreatePopover } from "@/components/board/todo-create-popover";
import { TodoEditDialog } from "@/components/board/todo-edit-dialog";
import { TodoProgressPie } from "@/components/board/todo-progress-pie";
import { EditGroupDialog } from "@/components/board/edit-group-dialog";
import { StatusUpdateDialog } from "@/components/board/status-update-dialog";
import { ConfirmDeleteDialog } from "@/components/confirm-delete-dialog";
import type { GroupDTO, TodoDTO } from "@/types/board";

// Compact's "+" -- sits inline on the last visible to-do row (its sibling
// text button is flex-1, so this shrink-0 trigger naturally lands at the
// row's right edge) instead of on a row of its own.
function AddTodoMenu({
  group,
  aiConfigured,
  onAddClick,
  onAiClick,
}: {
  group: GroupDTO;
  aiConfigured: boolean;
  onAddClick: () => void;
  onAiClick: () => void;
}) {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger
        render={
          <button
            className="flex size-6 shrink-0 items-center justify-center self-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground"
            aria-label={`Add a to-do to ${group.title}`}
          >
            <Plus className="size-3.5" />
          </button>
        }
      />
      <DropdownMenuContent align="end">
        <DropdownMenuItem onClick={onAddClick}>
          <Plus className="size-4" />
          Add to-do
        </DropdownMenuItem>
        {aiConfigured && (
          <DropdownMenuItem onClick={onAiClick}>
            <Sparkles className="size-4" />
            Add using AI
          </DropdownMenuItem>
        )}
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

export function GroupCard({ group }: { group: GroupDTO }) {
  const { toggleTodoDone, removeGroup, archiveGroup, aiConfigured } = useBoard();
  const { view } = useBoardView();
  const { holds, beginHold, cancelHold } = useHoldOnComplete();
  const compact = view === "compact";
  // True for any theme whose surfaces are dark -- Dark and Ocean both use
  // their `dark` color variant (see lib/colors.ts); light themes use `light`.
  const isDark = isDarkTheme();
  const [editingTodo, setEditingTodo] = useState<TodoDTO | null>(null);
  const [editOpen, setEditOpen] = useState(false);
  const [confirmOpen, setConfirmOpen] = useState(false);
  const [todoAiOpen, setTodoAiOpen] = useState(false);
  const [todoCreateOpen, setTodoCreateOpen] = useState(false);
  const [statusUpdateOpen, setStatusUpdateOpen] = useState(false);
  const [expandedWhileComplete, setExpandedWhileComplete] = useState(false);

  const {
    attributes,
    listeners,
    setNodeRef,
    setActivatorNodeRef,
    transform,
    transition,
    isDragging,
    isOver,
  } = useSortable({
    id: group.id,
    data: { type: "group", categoryId: group.categoryId },
  });
  // Another card is being dragged and is currently hovering over this one
  // -- signal "it'll land near here" with a ring, distinct from this
  // card's own accent-colored border. (isDragging guards against this
  // card ever ringing itself while it's the one being moved.)
  const isDropTarget = isOver && !isDragging;

  const color = getGroupColor(group.color);
  const borderColor = isDark ? color.dark : color.light;
  // The card fill is a calm, hand-picked tint of the same stroke color
  // (`soft` / `softDark` in lib/colors.ts), blended a little into the theme's
  // own card surface so it sits naturally on any theme -- the 85% weight
  // keeps the tint in charge while still letting a tinted theme surface show
  // through. Dark themes use `softDark`: the same hue at a dark-surface
  // lightness, instead of the near-white pastel of `soft`.
  const backgroundColor = `color-mix(in srgb, ${isDark ? color.softDark : color.soft} 85%, var(--card))`;
  // Opposing hue from the group's own color, for the progress pie below --
  // so it reads as a distinct accent rather than blending into the border.
  const pieAccentColor = getComplementaryColor(
    isDark ? color.dark : color.light,
    isDark ? "dark" : "light"
  );
  // Un-checked to-do text: a brighter tint of the group's own color rather
  // than the default (near-white in dark mode) foreground, so the group
  // title reads as the most prominent thing on the card.
  const todoTextColor = getBrighterColor(borderColor, isDark ? "dark" : "light");

  // Only offer archiving once there's actually something done -- a group
  // with no to-dos yet, or with any still open, isn't "finished" yet.
  const canArchive = group.todos.length > 0 && group.todos.every((t) => t.completed);
  const completedCount = group.todos.filter((t) => t.completed).length;
  // Compact surfaces open work, plus anything still mid-hold after being
  // freshly checked off (see useCompactHold) -- it stays on screen,
  // crossed out, through its fade before actually dropping out of the list.
  const visibleTodos = compact
    ? group.todos.filter((t) => !t.completed || holds.has(t.id))
    : group.todos;
  // The "+" rides on the last still-open row (see isLastRow below), not
  // necessarily the last row overall -- a held to-do can be lingering at
  // the tail while it fades out. -1 when every visible row is mid-hold,
  // which the fallback block below covers.
  let lastOpenTodoIndex = -1;
  if (compact) {
    visibleTodos.forEach((t, i) => {
      if (!t.completed) lastOpenTodoIndex = i;
    });
  }

  // In the default view, a fully-checked-off group collapses down to just
  // its header (title, notes icon, kebab menu) with a disclosure triangle
  // in place of the drag-grip dots, so a board full of "done" groups
  // doesn't stay as visually loud as one still full of open work. The
  // triangle re-expands it back to the normal full card. Compact already
  // hides finished groups outright (see CategoryLane), so this only
  // applies to the default view.
  const showDisclosure = !compact && canArchive;
  // Reset back to collapsed each time the group freshly becomes fully
  // done, rather than remembering a stale expanded choice from its last
  // completion cycle. Adjusting state during render (comparing against
  // last render's value) instead of in a useEffect avoids an extra render
  // pass -- see https://react.dev/learn/you-might-not-need-an-effect.
  const [wasComplete, setWasComplete] = useState(canArchive);
  if (canArchive !== wasComplete) {
    setWasComplete(canArchive);
    if (canArchive) setExpandedWhileComplete(false);
  }
  const isCollapsed = showDisclosure && !expandedWhileComplete;

  return (
    <>
      <div
        ref={setNodeRef}
        data-group-card=""
        style={{
          transform: CSS.Transform.toString(transform),
          transition,
          borderColor,
          backgroundColor,
        }}
        className={cn(
          "relative rounded-2xl border-[3px] p-3 shadow-sm transition-shadow",
          "hover:-translate-y-0.5 hover:shadow-md",
          isDragging && "opacity-50 shadow-lg",
          isDropTarget && "ring-2 ring-primary ring-offset-2 ring-offset-background"
        )}
      >
        <div className="flex items-start justify-between gap-1">
          <div
            ref={setActivatorNodeRef}
            {...attributes}
            {...listeners}
            className="group flex min-w-0 flex-1 cursor-grab touch-none items-start gap-1 rounded-md outline-none active:cursor-grabbing focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1"
            aria-label={`Drag to move ${group.title}`}
          >
            {showDisclosure ? (
              <button
                type="button"
                onClick={(e) => {
                  e.stopPropagation();
                  setExpandedWhileComplete((v) => !v);
                }}
                className="mt-1 flex shrink-0 items-center justify-center text-muted-foreground/60 hover:text-foreground"
                aria-label={expandedWhileComplete ? `Collapse ${group.title}` : `Expand ${group.title}`}
                aria-expanded={expandedWhileComplete}
              >
                <ChevronRight
                  className={cn("size-4 transition-transform", expandedWhileComplete && "rotate-90")}
                />
              </button>
            ) : (
              <span className="mt-1 flex shrink-0 items-center justify-center text-muted-foreground/60 group-hover:text-muted-foreground">
                <GripVertical className="size-4" />
              </span>
            )}
            <h3 className="min-w-0 flex-1 truncate pt-1 font-heading text-[15px] font-semibold tracking-tight">
              {group.title}
            </h3>
          </div>
          <div className="flex shrink-0 items-center">
            <NotesDialog group={group} />
            <DropdownMenu>
              <DropdownMenuTrigger
                render={
                  <button
                    className="flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground"
                    aria-label={`More options for ${group.title}`}
                  >
                    <MoreVertical className="size-4" />
                  </button>
                }
              />
              <DropdownMenuContent align="end">
                <DropdownMenuItem onClick={() => setEditOpen(true)}>
                  <Pencil className="size-4" />
                  Edit
                </DropdownMenuItem>
                {aiConfigured && (
                  <DropdownMenuItem onClick={() => setStatusUpdateOpen(true)}>
                    <ClipboardList className="size-4" />
                    Status Update
                  </DropdownMenuItem>
                )}
                <DropdownMenuSeparator />
                <DropdownMenuItem variant="destructive" onClick={() => setConfirmOpen(true)}>
                  <Trash2 className="size-4" />
                  Delete group
                </DropdownMenuItem>
              </DropdownMenuContent>
            </DropdownMenu>
          </div>
        </div>

        {!isCollapsed && (
          <>
            <ul className="mt-2 space-y-0.5">
              {visibleTodos.map((todo, index) => {
                const todoButton = (
                  <button
                    type="button"
                    onClick={() => setEditingTodo(todo)}
                    style={todo.completed ? undefined : { color: todoTextColor }}
                    className={cn(
                      "-mx-1 flex min-w-0 flex-1 items-center gap-1 rounded-md px-1 text-left text-sm transition-colors hover:bg-foreground/5",
                      todo.completed && "text-muted-foreground line-through hover:bg-transparent"
                    )}
                  >
                    <span className="min-w-0 truncate">{todo.title}</span>
                    {todo.details && (
                      <StickyNote className="size-3 shrink-0 text-muted-foreground/70" />
                    )}
                  </button>
                );

                // In compact, the "+" rides along on the last *open* row
                // instead of taking a row of its own -- a to-do mid-hold
                // (see useCompactHold) can be lingering after it, fading
                // out, so this isn't simply the last row overall.
                const isLastRow = compact && index === lastOpenTodoIndex;
                // Held to-dos are the only completed ones compact ever
                // keeps mounted (see visibleTodos above); everywhere else
                // this is undefined and the row renders at rest, exactly
                // as before.
                const holdPhase = compact ? holds.get(todo.id) : undefined;

                return (
                  <li
                    key={todo.id}
                    className="grid transition-[grid-template-rows] duration-200 ease-in"
                    style={{ gridTemplateRows: holdPhase === "collapsing" ? "0fr" : "1fr" }}
                  >
                    <div className="overflow-hidden">
                      <div
                        className="flex items-start gap-2 py-0.5 transition-opacity duration-1000 ease-in"
                        style={{
                          opacity: holdPhase === "fading" || holdPhase === "collapsing" ? 0 : 1,
                        }}
                      >
                        <TodoCheckbox
                          checked={todo.completed}
                          onCheckedChange={(checked) => {
                            toggleTodoDone(todo.id, group.id, group.categoryId, checked);
                            if (!compact) return;
                            // Checking off holds it on screen for a grace
                            // period; unchecking -- including as a
                            // change-of-mind mid-hold -- cancels that hold
                            // outright so it snaps back to a normal open row.
                            if (checked) beginHold(todo.id);
                            else cancelHold(todo.id);
                          }}
                          accentColor={borderColor}
                          isDark={isDark}
                          className="mt-0.5"
                          aria-label={`Mark "${todo.title}" ${todo.completed ? "incomplete" : "complete"}`}
                        />
                        {todo.details ? (
                          <MouseFollowTooltip content={todo.details}>{todoButton}</MouseFollowTooltip>
                        ) : (
                          todoButton
                        )}
                        {isLastRow && (
                          <AddTodoMenu
                            group={group}
                            aiConfigured={aiConfigured}
                            onAddClick={() => setTodoCreateOpen(true)}
                            onAiClick={() => setTodoAiOpen(true)}
                          />
                        )}
                      </div>
                    </div>
                  </li>
                );
              })}
            </ul>

            {compact ? (
              // No open row to ride on -- either every to-do here is
              // mid-hold after being freshly checked off (about to clear
              // the group entirely once its fade finishes), or, as a
              // defensive fallback that shouldn't otherwise happen,
              // CategoryLane failed to hide an already-empty group.
              lastOpenTodoIndex === -1 && (
                <div className="mt-1 flex justify-end">
                  <AddTodoMenu
                    group={group}
                    onAddClick={() => setTodoCreateOpen(true)}
                    onAiClick={() => setTodoAiOpen(true)}
                    aiConfigured={aiConfigured}
                  />
                </div>
              )
            ) : (
              <>
                <div className="mt-2">
                  <TodoCreatePopover groupId={group.id} categoryId={group.categoryId} />
                </div>

                {aiConfigured && (
                  <Button
                    variant="ghost"
                    size="sm"
                    className="w-full justify-start gap-2 text-muted-foreground"
                    onClick={() => setTodoAiOpen(true)}
                  >
                    <Sparkles className="size-3.5" />
                    Add using AI
                  </Button>
                )}

                {(canArchive || group.todos.length > 0) && (
                  <div className="mt-1 flex items-center gap-1 border-t border-foreground/[0.07] pt-1.5">
                    {canArchive && (
                      <Tooltip>
                        <TooltipTrigger
                          render={
                            <Button
                              variant="ghost"
                              size="icon-sm"
                              className="shrink-0 text-muted-foreground"
                              onClick={() => archiveGroup(group.id, group.categoryId)}
                              aria-label="Archive group"
                            >
                              <Archive className="size-3.5" />
                            </Button>
                          }
                        />
                        <TooltipContent side="top">Archive (all to-dos done)</TooltipContent>
                      </Tooltip>
                    )}
                    <span className="ml-auto text-[11px] font-medium tabular-nums text-muted-foreground">
                      {completedCount}/{group.todos.length} done
                    </span>
                  </div>
                )}

                <TodoProgressPie
                  completed={completedCount}
                  total={group.todos.length}
                  accentColor={pieAccentColor}
                />
              </>
            )}
          </>
        )}
      </div>

      {editingTodo && (
        <TodoEditDialog
          todo={editingTodo}
          groupId={group.id}
          categoryId={group.categoryId}
          open={!!editingTodo}
          onOpenChange={(open) => !open && setEditingTodo(null)}
        />
      )}

      <EditGroupDialog group={group} open={editOpen} onOpenChange={setEditOpen} />

      <TodoAiDialog group={group} open={todoAiOpen} onOpenChange={setTodoAiOpen} />

      <TodoCreateDialog
        groupId={group.id}
        categoryId={group.categoryId}
        open={todoCreateOpen}
        onOpenChange={setTodoCreateOpen}
      />

      <StatusUpdateDialog group={group} open={statusUpdateOpen} onOpenChange={setStatusUpdateOpen} />

      <ConfirmDeleteDialog
        open={confirmOpen}
        onOpenChange={setConfirmOpen}
        title="Delete group?"
        description={`Delete "${group.title}" and all of its to-dos? This can't be undone.`}
        onConfirm={() => removeGroup(group.id, group.categoryId)}
      />
    </>
  );
}
