"use client";

import { useState, useMemo } from "react";
import {
  DndContext,
  closestCorners,
  MouseSensor,
  TouchSensor,
  useSensor,
  useSensors,
  type DragEndEvent,
  type DragStartEvent,
  DragOverlay,
} from "@dnd-kit/core";
import {
  SortableContext,
  useSortable,
  verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import {
  Circle,
  CheckCircle2,
  Calendar,
  GripVertical,
  Plus,
  MoreHorizontal,
  Pencil,
  Trash2,
  X,
  Check,
  User2,
  Flag,
} from "lucide-react";
import { cn, formatRelativeDate, isTaskDeadlineOverdue } from "@/lib/utils";
import type { TaskWithRelations } from "@/hooks/use-tasks";
import type { TaskStatus } from "@/types";

interface Bucket {
  id: string;
  title: string;
  status: TaskStatus;
  color: string;
}

const DEFAULT_BUCKETS: Bucket[] = [
  { id: "bucket-todo", title: "To-Do", status: "todo", color: "#6366f1" },
  { id: "bucket-in-progress", title: "In Bearbeitung", status: "in_progress", color: "#f59e0b" },
  { id: "bucket-done", title: "Erledigt", status: "done", color: "#10b981" },
];

// tasks.status is a fixed 4-value DB enum (see migration 00001), so at most
// four distinct buckets can ever exist — adding one beyond that would have
// to reuse a status already used by another bucket, making both columns
// show/save the exact same underlying tasks.
const ALL_STATUSES: TaskStatus[] = ["todo", "in_progress", "done", "cancelled"];
const STATUS_TITLES: Record<TaskStatus, string> = {
  todo: "Neues Bucket",
  in_progress: "In Bearbeitung",
  done: "Erledigt",
  cancelled: "Abgebrochen",
};

const BUCKET_STORAGE_KEY = "mindavio-kanban-buckets";

function loadBuckets(): Bucket[] {
  if (typeof window === "undefined") return DEFAULT_BUCKETS;
  try {
    const stored = localStorage.getItem(BUCKET_STORAGE_KEY);
    if (stored) {
      const parsed = JSON.parse(stored) as Bucket[];
      // Self-heal boards saved before duplicate statuses were prevented —
      // keep only the first bucket per status so columns stop sharing tasks.
      const seen = new Set<TaskStatus>();
      const deduped = parsed.filter((bucket) => {
        if (seen.has(bucket.status)) return false;
        seen.add(bucket.status);
        return true;
      });
      if (deduped.length !== parsed.length) saveBuckets(deduped);
      return deduped;
    }
  } catch {}
  return DEFAULT_BUCKETS;
}

function saveBuckets(buckets: Bucket[]) {
  localStorage.setItem(BUCKET_STORAGE_KEY, JSON.stringify(buckets));
}

const PRIORITY_DOT: Record<string, string> = {
  urgent: "#ef4444",
  high: "#f97316",
  medium: "#eab308",
  low: "#3b82f6",
};

// ─── Sortable Task Card ─────────────────────────────────────
function SortableTaskCard({
  task,
  onToggle,
  onClick,
  editable,
  currentUserId,
}: {
  task: TaskWithRelations;
  onToggle: () => void;
  onClick: () => void;
  editable: boolean;
  currentUserId?: string | null;
}) {
  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
    isDragging,
  } = useSortable({
    id: task.id,
    data: { type: "task", status: task.status },
    disabled: !editable,
  });

  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isDragging ? 0.4 : 1,
  };

  return (
    <div ref={setNodeRef} style={style} className="group/card">
      <TaskKanbanCard
        task={task}
        onToggle={onToggle}
        onClick={onClick}
        editable={editable}
        currentUserId={currentUserId}
        dragHandleProps={{ ...attributes, ...listeners }}
      />
    </div>
  );
}

function TaskKanbanCard({
  task,
  onToggle,
  onClick,
  editable = true,
  dragHandleProps,
  currentUserId,
}: {
  task: TaskWithRelations;
  onToggle: () => void;
  onClick: () => void;
  editable?: boolean;
  dragHandleProps?: Record<string, unknown>;
  currentUserId?: string | null;
}) {
  const isDone = task.status === "done";
  const isOverdue = task.deadline && !isDone && isTaskDeadlineOverdue(task.deadline);
  const prioColor = PRIORITY_DOT[task.priority];
  const needsMyLead =
    (!!currentUserId &&
      task.reviewer_id === currentUserId &&
      task.review_status === "pending_review") ||
    (!!currentUserId &&
      task.assignee_id === currentUserId &&
      task.review_status === "changes_requested");

  return (
    <div
      className={cn(
        "rounded-xl border p-3 transition-all duration-150 cursor-pointer shadow-sm hover:shadow-md",
        needsMyLead
          ? "border-amber-500/40 bg-amber-500/[0.05] hover:border-amber-500/60"
          : "border-border/50 bg-card hover:border-border"
      )}
      onClick={onClick}
    >
      <div className="flex items-start gap-2">
        {/* Drag handle */}
        <button
          className="shrink-0 mt-0.5 opacity-0 group-hover/card:opacity-100 transition-opacity cursor-grab active:cursor-grabbing p-0.5"
          {...dragHandleProps}
          onClick={(e) => e.stopPropagation()}
          disabled={!editable}
        >
          <GripVertical className="h-3.5 w-3.5 text-muted-foreground/50" />
        </button>

        {/* Checkbox */}
        <button
          onClick={(e) => {
            e.stopPropagation();
            onToggle();
          }}
          disabled={!editable}
          className="shrink-0 mt-0.5 cursor-pointer text-muted-foreground hover:text-foreground transition-colors"
        >
          {isDone ? (
            <CheckCircle2 className="h-4 w-4 text-emerald-500" />
          ) : (
            <Circle className="h-4 w-4" />
          )}
        </button>

        {/* Content */}
        <div className="flex-1 min-w-0">
          <span
            className={cn(
              "text-[13px] font-medium leading-snug block",
              isDone && "line-through text-muted-foreground/60"
            )}
          >
            {task.title}
          </span>

          {/* Meta */}
          <div className="flex items-center gap-2 mt-1.5 flex-wrap">
            {prioColor && task.priority !== "none" && (
              <span
                className="w-1.5 h-1.5 rounded-full shrink-0"
                style={{ backgroundColor: prioColor }}
              />
            )}
            {task.deadline && (
              <span
                className={cn(
                  "inline-flex items-center gap-1 text-[10px]",
                  isOverdue ? "text-red-500" : "text-muted-foreground"
                )}
              >
                <Calendar className="h-2.5 w-2.5" />
                {formatRelativeDate(task.deadline)}
              </span>
            )}
            {task.assignee && (
              <span className="inline-flex items-center gap-1 text-[10px] text-muted-foreground">
                <User2 className="h-2.5 w-2.5" />
                {task.assignee.full_name || task.assignee.email}
              </span>
            )}
            {needsMyLead && (
              <span className="inline-flex items-center gap-1 rounded-full bg-amber-500/15 px-1.5 py-0 text-[9px] font-semibold text-amber-700 dark:text-amber-400">
                <Flag className="h-2.5 w-2.5" />
                Take the lead
              </span>
            )}
            {task.tags.slice(0, 2).map((tag) => (
              <span
                key={tag.id}
                className="rounded-full px-1.5 py-0 text-[9px] font-medium"
                style={{ backgroundColor: tag.color + "18", color: tag.color }}
              >
                {tag.name}
              </span>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

// ─── Kanban Column ──────────────────────────────────────────
function KanbanColumn({
  bucket,
  tasks,
  onToggle,
  onClick,
  onRenameBucket,
  onDeleteBucket,
  canDelete,
  editable = true,
  currentUserId,
}: {
  bucket: Bucket;
  tasks: TaskWithRelations[];
  onToggle: (id: string, status: string) => void;
  onClick: (task: TaskWithRelations) => void;
  onRenameBucket: (id: string, name: string) => void;
  onDeleteBucket: (id: string) => void;
  canDelete: boolean;
  editable?: boolean;
  currentUserId?: string | null;
}) {
  const [menuOpen, setMenuOpen] = useState(false);
  const [renaming, setRenaming] = useState(false);
  const [renameValue, setRenameValue] = useState(bucket.title);

  const { setNodeRef } = useSortable({
    id: bucket.id,
    data: { type: "column", status: bucket.status },
    disabled: true,
  });

  function handleRename() {
    if (renameValue.trim()) {
      onRenameBucket(bucket.id, renameValue.trim());
    }
    setRenaming(false);
    setMenuOpen(false);
  }

  return (
    <div
      ref={setNodeRef}
      className="flex flex-col min-w-[280px] w-[320px] shrink-0 lg:w-auto lg:flex-1"
    >
      {/* Column header */}
      <div className="flex items-center justify-between mb-3 px-1">
        <div className="flex items-center gap-2.5">
          <div
            className="w-2.5 h-2.5 rounded-full"
            style={{ backgroundColor: bucket.color }}
          />
          {renaming ? (
            <div className="flex items-center gap-1">
              <input
                value={renameValue}
                onChange={(e) => setRenameValue(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === "Enter") handleRename();
                  if (e.key === "Escape") { setRenaming(false); setRenameValue(bucket.title); }
                }}
                className="text-sm font-semibold bg-transparent border-b border-border focus:border-foreground outline-none w-32"
                autoFocus
              />
              <button onClick={handleRename} className="p-0.5 hover:bg-accent rounded">
                <Check className="h-3.5 w-3.5 text-emerald-500" />
              </button>
              <button onClick={() => { setRenaming(false); setRenameValue(bucket.title); }} className="p-0.5 hover:bg-accent rounded">
                <X className="h-3.5 w-3.5 text-muted-foreground" />
              </button>
            </div>
          ) : (
            <h3 className="text-sm font-semibold tracking-tight">{bucket.title}</h3>
          )}
          <span className="text-[10px] font-medium text-muted-foreground bg-muted rounded-full px-2 py-0.5 tabular-nums">
            {tasks.length}
          </span>
        </div>

        {/* Bucket menu */}
        {!renaming && (
          <div className="relative">
            <button
              onClick={() => setMenuOpen(!menuOpen)}
              className="p-1 rounded-md hover:bg-accent transition-colors text-muted-foreground hover:text-foreground"
            >
              <MoreHorizontal className="h-4 w-4" />
            </button>
            {menuOpen && (
              <>
                <div className="fixed inset-0 z-40" onClick={() => setMenuOpen(false)} />
                <div className="absolute right-0 top-8 z-50 w-40 rounded-xl border border-border bg-popover shadow-lg py-1">
                  <button
                    className="flex items-center gap-2 w-full px-3 py-2 text-sm hover:bg-accent transition-colors text-left"
                    onClick={() => { setRenaming(true); setMenuOpen(false); }}
                  >
                    <Pencil className="h-3.5 w-3.5" />
                    Umbenennen
                  </button>
                  {canDelete && (
                    <button
                      className="flex items-center gap-2 w-full px-3 py-2 text-sm hover:bg-accent transition-colors text-left text-red-500"
                      onClick={() => { onDeleteBucket(bucket.id); setMenuOpen(false); }}
                    >
                      <Trash2 className="h-3.5 w-3.5" />
                      Löschen
                    </button>
                  )}
                </div>
              </>
            )}
          </div>
        )}
      </div>

      {/* Cards */}
      <div className="flex-1 rounded-xl bg-muted/30 border border-border/30 p-2 space-y-2 min-h-[200px]">
        <SortableContext
          items={tasks.map((t) => t.id)}
          strategy={verticalListSortingStrategy}
        >
          {tasks.map((task) => (
            <SortableTaskCard
              key={task.id}
              task={task}
              onToggle={() => onToggle(task.id, task.status)}
              onClick={() => onClick(task)}
              editable={editable}
              currentUserId={currentUserId}
            />
          ))}
        </SortableContext>

        {tasks.length === 0 && (
          <div className="flex items-center justify-center h-20 text-[11px] text-muted-foreground">
            Aufgaben hierher ziehen
          </div>
        )}
      </div>
    </div>
  );
}

// ─── Main Kanban Board ──────────────────────────────────────
interface TaskKanbanProps {
  tasks: TaskWithRelations[];
  onToggle: (id: string, status: string) => void;
  onClick: (task: TaskWithRelations) => void;
  onUpdateStatus: (id: string, status: TaskStatus) => void;
  editable?: boolean;
  currentUserId?: string | null;
}

export function TaskKanban({
  tasks,
  onToggle,
  onClick,
  onUpdateStatus,
  editable = true,
  currentUserId,
}: TaskKanbanProps) {
  const [buckets, setBuckets] = useState<Bucket[]>(loadBuckets);
  const [activeId, setActiveId] = useState<string | null>(null);

  const sensors = useSensors(
    useSensor(MouseSensor, { activationConstraint: { distance: 5 } }),
    useSensor(TouchSensor, { activationConstraint: { delay: 200, tolerance: 8 } })
  );

  // Group tasks by bucket status
  const tasksByStatus = useMemo(() => {
    const map = new Map<TaskStatus, TaskWithRelations[]>();
    for (const bucket of buckets) {
      map.set(bucket.status, []);
    }
    for (const task of tasks) {
      const list = map.get(task.status);
      if (list) {
        list.push(task);
      } else {
        // Task has a status not matching any bucket — put in first bucket
        const first = map.get(buckets[0]?.status);
        if (first) first.push(task);
      }
    }
    return map;
  }, [tasks, buckets]);

  const activeTask = activeId ? tasks.find((t) => t.id === activeId) : null;

  function handleDragStart(event: DragStartEvent) {
    if (!editable) return;
    setActiveId(event.active.id as string);
  }

  function handleDragOver() {
    // Not needed for simple column drop
  }

  function handleDragEnd(event: DragEndEvent) {
    if (!editable) return;
    setActiveId(null);
    const { active, over } = event;
    if (!over) return;

    const taskId = active.id as string;
    const task = tasks.find((t) => t.id === taskId);
    if (!task) return;

    // Find which bucket the task was dropped into
    const overData = over.data.current;
    let targetStatus: TaskStatus | null = null;

    if (overData?.type === "column") {
      targetStatus = overData.status as TaskStatus;
    } else if (overData?.type === "task") {
      // Dropped onto another task — find that task's status
      const overTask = tasks.find((t) => t.id === over.id);
      if (overTask) targetStatus = overTask.status;
    } else {
      // Could be dropping on a bucket container
      const bucket = buckets.find((b) => b.id === over.id);
      if (bucket) targetStatus = bucket.status;
    }

    if (targetStatus && targetStatus !== task.status) {
      onUpdateStatus(taskId, targetStatus);
    }
  }

  function handleRenameBucket(id: string, name: string) {
    if (!editable) return;
    setBuckets((prev) => {
      const updated = prev.map((b) => (b.id === id ? { ...b, title: name } : b));
      saveBuckets(updated);
      return updated;
    });
  }

  function handleDeleteBucket(id: string) {
    if (!editable) return;
    setBuckets((prev) => {
      const updated = prev.filter((b) => b.id !== id);
      saveBuckets(updated);
      return updated;
    });
  }

  function handleAddBucket() {
    if (!editable) return;
    const usedStatuses = new Set(buckets.map((b) => b.status));
    const nextStatus = ALL_STATUSES.find((status) => !usedStatuses.has(status));
    // Every status already has a bucket — a new one would silently share
    // tasks with whichever existing bucket it reused, so refuse instead.
    if (!nextStatus) return;
    const newBucket: Bucket = {
      id: `bucket-${Date.now()}`,
      title: STATUS_TITLES[nextStatus],
      status: nextStatus,
      color: "#71717a",
    };
    setBuckets((prev) => {
      const updated = [...prev, newBucket];
      saveBuckets(updated);
      return updated;
    });
  }

  const canAddBucket = editable && buckets.length < ALL_STATUSES.length;

  return (
    <div className="space-y-4">
      <DndContext
        sensors={sensors}
        collisionDetection={closestCorners}
        onDragStart={handleDragStart}
        onDragOver={handleDragOver}
        onDragEnd={handleDragEnd}
      >
        <div className="flex gap-4 overflow-x-auto pb-4 -mx-2 px-2">
          {buckets.map((bucket) => (
            <KanbanColumn
              key={bucket.id}
              bucket={bucket}
              tasks={tasksByStatus.get(bucket.status) || []}
              onToggle={onToggle}
              onClick={onClick}
              onRenameBucket={handleRenameBucket}
              onDeleteBucket={handleDeleteBucket}
              canDelete={buckets.length > 1}
              editable={editable}
              currentUserId={currentUserId}
            />
          ))}

          {/* Add bucket button */}
          {canAddBucket && (
            <div className="min-w-[200px] shrink-0">
            <button
              onClick={handleAddBucket}
              className="flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground px-3 py-2 rounded-xl border border-dashed border-border/50 hover:border-border transition-all w-full justify-center mt-8"
            >
              <Plus className="h-4 w-4" />
              Bucket hinzufügen
            </button>
            </div>
          )}
        </div>

        {/* Drag overlay */}
        <DragOverlay>
          {activeTask && (
            <div className="w-[300px]">
              <TaskKanbanCard
                task={activeTask}
                onToggle={() => {}}
                onClick={() => {}}
                editable={editable}
                currentUserId={currentUserId}
              />
            </div>
          )}
        </DragOverlay>
      </DndContext>
    </div>
  );
}
