"use client";

import { useState, useEffect, useCallback, useMemo, useRef } from "react";
import type { ReactElement } from "react";
import { useSearchParams, useRouter } from "next/navigation";
import { DragDropContext, Droppable, Draggable } from "@hello-pangea/dnd";
import type {
  DropResult,
  DroppableProvided,
  DraggableProvided,
  DraggableStateSnapshot,
} from "@hello-pangea/dnd";

import { MosaicSpinner } from "@/components/ui/MosaicSpinner";
import { fetchTasks, updateTask, createTask, type TaskFilters } from "@/lib/api/tasks";
import { fetchProjects, type Project } from "@/lib/api/projects";
import { useWorkspaceId } from "@/lib/hooks";
import type { Task } from "@mosaic/shared";
import { TaskStatus, TaskPriority } from "@mosaic/shared";

/* ---------------------------------------------------------------------------
   Column configuration
   --------------------------------------------------------------------------- */

interface ColumnConfig {
  status: TaskStatus;
  label: string;
  accent: string;
}

const COLUMNS: ColumnConfig[] = [
  { status: TaskStatus.NOT_STARTED, label: "To Do", accent: "var(--ms-blue-400)" },
  { status: TaskStatus.IN_PROGRESS, label: "In Progress", accent: "var(--ms-amber-400)" },
  { status: TaskStatus.PAUSED, label: "Paused", accent: "var(--ms-purple-400)" },
  { status: TaskStatus.COMPLETED, label: "Done", accent: "var(--ms-teal-400)" },
  { status: TaskStatus.ARCHIVED, label: "Archived", accent: "var(--muted)" },
];

const PRIORITY_OPTIONS: { value: string; label: string }[] = [
  { value: "", label: "All Priorities" },
  { value: TaskPriority.HIGH, label: "High" },
  { value: TaskPriority.MEDIUM, label: "Medium" },
  { value: TaskPriority.LOW, label: "Low" },
];

/* ---------------------------------------------------------------------------
   Filter select shared styles
   --------------------------------------------------------------------------- */

const selectStyle: React.CSSProperties = {
  padding: "6px 10px",
  borderRadius: "var(--r)",
  border: "1px solid var(--border)",
  background: "var(--surface)",
  color: "var(--text)",
  fontSize: "0.83rem",
  outline: "none",
  minWidth: 130,
};

const inputStyle: React.CSSProperties = {
  ...selectStyle,
  minWidth: 180,
};

/* ---------------------------------------------------------------------------
   Priority badge helper
   --------------------------------------------------------------------------- */

interface PriorityStyle {
  label: string;
  bg: string;
  color: string;
}

function getPriorityStyle(priority: TaskPriority): PriorityStyle {
  switch (priority) {
    case TaskPriority.HIGH:
      return { label: "High", bg: "rgba(229,72,77,0.15)", color: "var(--danger)" };
    case TaskPriority.MEDIUM:
      return { label: "Medium", bg: "rgba(245,158,11,0.15)", color: "var(--warn)" };
    case TaskPriority.LOW:
      return { label: "Low", bg: "rgba(143,157,183,0.15)", color: "var(--muted)" };
    default:
      return { label: String(priority), bg: "rgba(143,157,183,0.15)", color: "var(--muted)" };
  }
}

/* ---------------------------------------------------------------------------
   Task Card
   --------------------------------------------------------------------------- */

interface TaskCardProps {
  task: Task;
  provided: DraggableProvided;
  snapshot: DraggableStateSnapshot;
  columnAccent: string;
}

function TaskCard({ task, provided, snapshot, columnAccent }: TaskCardProps): ReactElement {
  const [hovered, setHovered] = useState(false);
  const priorityStyle = getPriorityStyle(task.priority);

  return (
    <div
      ref={provided.innerRef}
      {...provided.draggableProps}
      {...provided.dragHandleProps}
      onMouseEnter={() => {
        setHovered(true);
      }}
      onMouseLeave={() => {
        setHovered(false);
      }}
      style={{
        background: "var(--surface)",
        border: `1px solid ${hovered || snapshot.isDragging ? columnAccent : "var(--border)"}`,
        borderRadius: "var(--r)",
        padding: 12,
        marginBottom: 8,
        cursor: "grab",
        transition: "border-color 0.15s, box-shadow 0.15s",
        boxShadow: snapshot.isDragging ? "var(--shadow-lg)" : "none",
        ...provided.draggableProps.style,
      }}
    >
      {/* Title */}
      <div
        style={{
          fontWeight: 600,
          color: "var(--text)",
          fontSize: "0.875rem",
          marginBottom: 6,
          overflow: "hidden",
          textOverflow: "ellipsis",
          whiteSpace: "nowrap",
        }}
      >
        {task.title}
      </div>

      {/* Priority badge */}
      <span
        style={{
          display: "inline-block",
          padding: "1px 8px",
          borderRadius: "var(--r-sm)",
          background: priorityStyle.bg,
          color: priorityStyle.color,
          fontSize: "0.7rem",
          fontWeight: 500,
          marginBottom: 6,
        }}
      >
        {priorityStyle.label}
      </span>

      {/* Description */}
      {task.description && (
        <p
          style={{
            color: "var(--muted)",
            fontSize: "0.8rem",
            margin: 0,
            overflow: "hidden",
            textOverflow: "ellipsis",
            display: "-webkit-box",
            WebkitLineClamp: 2,
            WebkitBoxOrient: "vertical",
            lineHeight: 1.4,
          }}
        >
          {task.description}
        </p>
      )}
    </div>
  );
}

/* ---------------------------------------------------------------------------
   Kanban Column
   --------------------------------------------------------------------------- */

interface KanbanColumnProps {
  config: ColumnConfig;
  tasks: Task[];
  onAddTask: (status: TaskStatus, title: string, projectId?: string) => Promise<void>;
  projectId?: string;
}

function KanbanColumn({ config, tasks, onAddTask, projectId }: KanbanColumnProps): ReactElement {
  const [showAddForm, setShowAddForm] = useState(false);
  const [inputValue, setInputValue] = useState("");
  const [isSubmitting, setIsSubmitting] = useState(false);
  const inputRef = useRef<HTMLInputElement>(null);

  // Focus input when form is shown
  useEffect(() => {
    if (showAddForm && inputRef.current) {
      inputRef.current.focus();
    }
  }, [showAddForm]);

  const handleSubmit = async (e: React.SyntheticEvent): Promise<void> => {
    e.preventDefault();
    if (!inputValue.trim() || isSubmitting) {
      return;
    }

    setIsSubmitting(true);
    try {
      await onAddTask(config.status, inputValue.trim(), projectId);
      setInputValue("");
      setShowAddForm(false);
    } catch (err) {
      console.error("[KanbanColumn] Failed to add task:", err);
    } finally {
      setIsSubmitting(false);
    }
  };

  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>): void => {
    if (e.key === "Escape") {
      setShowAddForm(false);
      setInputValue("");
    }
  };

  return (
    <div
      style={{
        minWidth: 280,
        maxWidth: 340,
        flex: "1 0 280px",
        display: "flex",
        flexDirection: "column",
        background: "var(--bg-mid)",
        borderRadius: "var(--r-lg)",
        overflow: "hidden",
      }}
    >
      {/* Column header */}
      <div
        style={{
          borderTop: `3px solid ${config.accent}`,
          padding: "12px 16px",
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
        }}
      >
        <span
          style={{
            fontWeight: 600,
            fontSize: "0.85rem",
            color: "var(--text)",
          }}
        >
          {config.label}
        </span>
        <span
          style={{
            display: "inline-flex",
            alignItems: "center",
            justifyContent: "center",
            minWidth: 22,
            height: 22,
            padding: "0 6px",
            borderRadius: "var(--r)",
            background: `color-mix(in srgb, ${config.accent} 15%, transparent)`,
            color: config.accent,
            fontSize: "0.75rem",
            fontWeight: 600,
            fontFamily: "var(--mono)",
          }}
        >
          {tasks.length}
        </span>
      </div>

      {/* Droppable area */}
      <Droppable droppableId={config.status}>
        {(provided: DroppableProvided) => (
          <div
            ref={provided.innerRef}
            {...provided.droppableProps}
            style={{
              padding: "8px 12px 12px",
              flex: 1,
              minHeight: 80,
              overflowY: "auto",
            }}
          >
            {tasks.map((task, index) => (
              <Draggable key={task.id} draggableId={task.id} index={index}>
                {(dragProvided: DraggableProvided, dragSnapshot: DraggableStateSnapshot) => (
                  <TaskCard
                    task={task}
                    provided={dragProvided}
                    snapshot={dragSnapshot}
                    columnAccent={config.accent}
                  />
                )}
              </Draggable>
            ))}
            {provided.placeholder}
          </div>
        )}
      </Droppable>

      {/* Add Task Form */}
      {!showAddForm ? (
        <button
          type="button"
          onClick={() => {
            setShowAddForm(true);
          }}
          style={{
            padding: "10px 16px",
            border: "none",
            background: "transparent",
            color: "var(--muted)",
            fontSize: "0.8rem",
            cursor: "pointer",
            textAlign: "left",
            transition: "color 0.15s",
            width: "100%",
          }}
          onMouseEnter={(e) => {
            e.currentTarget.style.color = "var(--text)";
          }}
          onMouseLeave={(e) => {
            e.currentTarget.style.color = "var(--muted)";
          }}
        >
          + Add task
        </button>
      ) : (
        <form
          onSubmit={handleSubmit}
          style={{ padding: "8px 12px 12px", borderTop: "1px solid var(--border)" }}
        >
          <input
            ref={inputRef}
            type="text"
            value={inputValue}
            onChange={(e) => {
              setInputValue(e.target.value);
            }}
            onKeyDown={handleKeyDown}
            placeholder="Task title..."
            disabled={isSubmitting}
            style={{
              width: "100%",
              padding: "8px 10px",
              borderRadius: "var(--r)",
              border: `1px solid ${inputValue ? "var(--primary)" : "var(--border)"}`,
              background: "var(--surface)",
              color: "var(--text)",
              fontSize: "0.85rem",
              outline: "none",
              opacity: isSubmitting ? 0.6 : 1,
            }}
            autoFocus
          />
          <div style={{ display: "flex", gap: 6, marginTop: 6 }}>
            <button
              type="submit"
              disabled={isSubmitting || !inputValue.trim()}
              style={{
                padding: "6px 12px",
                borderRadius: "var(--r)",
                border: "1px solid var(--primary)",
                background: "var(--primary)",
                color: "#fff",
                fontSize: "0.8rem",
                fontWeight: 500,
                cursor: isSubmitting || !inputValue.trim() ? "not-allowed" : "pointer",
                opacity: isSubmitting || !inputValue.trim() ? 0.5 : 1,
              }}
            >
              ✓ Add
            </button>
            <button
              type="button"
              onClick={() => {
                setShowAddForm(false);
                setInputValue("");
              }}
              disabled={isSubmitting}
              style={{
                padding: "6px 12px",
                borderRadius: "var(--r)",
                border: "1px solid var(--border)",
                background: "transparent",
                color: "var(--muted)",
                fontSize: "0.8rem",
                cursor: isSubmitting ? "not-allowed" : "pointer",
                opacity: isSubmitting ? 0.5 : 1,
              }}
            >
              Cancel
            </button>
          </div>
          <div style={{ marginTop: 6, fontSize: "0.75rem", color: "var(--muted)" }}>
            Press{" "}
            <kbd
              style={{
                padding: "2px 4px",
                background: "var(--bg-mid)",
                borderRadius: "2px",
                fontFamily: "var(--mono)",
              }}
            >
              Enter
            </kbd>{" "}
            to save,{" "}
            <kbd
              style={{
                padding: "2px 4px",
                background: "var(--bg-mid)",
                borderRadius: "2px",
                fontFamily: "var(--mono)",
              }}
            >
              Escape
            </kbd>{" "}
            to cancel
          </div>
        </form>
      )}
    </div>
  );
}

/* ---------------------------------------------------------------------------
   Filter Bar
   --------------------------------------------------------------------------- */

interface FilterBarProps {
  projects: Project[];
  projectId: string;
  priority: string;
  search: string;
  myTasks: boolean;
  onProjectChange: (value: string) => void;
  onPriorityChange: (value: string) => void;
  onSearchChange: (value: string) => void;
  onMyTasksToggle: () => void;
  onClear: () => void;
  hasActiveFilters: boolean;
}

function FilterBar({
  projects,
  projectId,
  priority,
  search,
  myTasks,
  onProjectChange,
  onPriorityChange,
  onSearchChange,
  onMyTasksToggle,
  onClear,
  hasActiveFilters,
}: FilterBarProps): ReactElement {
  return (
    <div
      style={{
        display: "flex",
        alignItems: "center",
        flexWrap: "wrap",
        gap: 8,
        padding: "10px 14px",
        background: "var(--surface)",
        border: "1px solid var(--border)",
        borderRadius: "var(--r-lg)",
        marginBottom: 16,
      }}
    >
      {/* Search */}
      <input
        type="text"
        placeholder="Search tasks..."
        value={search}
        onChange={(e): void => {
          onSearchChange(e.target.value);
        }}
        style={inputStyle}
      />

      {/* Project filter */}
      <select
        value={projectId}
        onChange={(e): void => {
          onProjectChange(e.target.value);
        }}
        style={selectStyle}
      >
        <option value="">All Projects</option>
        {projects.map((p) => (
          <option key={p.id} value={p.id}>
            {p.name}
          </option>
        ))}
      </select>

      {/* Priority filter */}
      <select
        value={priority}
        onChange={(e): void => {
          onPriorityChange(e.target.value);
        }}
        style={selectStyle}
      >
        {PRIORITY_OPTIONS.map((opt) => (
          <option key={opt.value} value={opt.value}>
            {opt.label}
          </option>
        ))}
      </select>

      {/* My Tasks toggle */}
      <button
        type="button"
        onClick={onMyTasksToggle}
        style={{
          padding: "6px 12px",
          borderRadius: "var(--r)",
          border: myTasks ? "1px solid var(--primary)" : "1px solid var(--border)",
          background: myTasks ? "var(--primary)" : "transparent",
          color: myTasks ? "#fff" : "var(--text-2)",
          fontSize: "0.83rem",
          fontWeight: 500,
          cursor: "pointer",
          transition: "all 0.12s ease",
          whiteSpace: "nowrap",
        }}
      >
        My Tasks
      </button>

      {/* Clear filters */}
      {hasActiveFilters && (
        <button
          type="button"
          onClick={onClear}
          style={{
            padding: "6px 12px",
            borderRadius: "var(--r)",
            border: "1px solid var(--border)",
            background: "transparent",
            color: "var(--muted)",
            fontSize: "0.83rem",
            fontWeight: 500,
            cursor: "pointer",
            whiteSpace: "nowrap",
          }}
        >
          Clear
        </button>
      )}
    </div>
  );
}

/* ---------------------------------------------------------------------------
   Kanban Board Page
   --------------------------------------------------------------------------- */

export default function KanbanPage(): ReactElement {
  const workspaceId = useWorkspaceId();
  const router = useRouter();
  const searchParams = useSearchParams();

  const [tasks, setTasks] = useState<Task[]>([]);
  const [projects, setProjects] = useState<Project[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  // Read filters from URL params
  const filterProject = searchParams.get("project") ?? "";
  const filterPriority = searchParams.get("priority") ?? "";
  const filterSearch = searchParams.get("q") ?? "";
  const filterMyTasks = searchParams.get("my") === "1";

  const hasActiveFilters =
    filterProject !== "" || filterPriority !== "" || filterSearch !== "" || filterMyTasks;

  /** Update a single URL param (preserving others) */
  const setParam = useCallback(
    (key: string, value: string) => {
      const params = new URLSearchParams(searchParams.toString());
      if (value) {
        params.set(key, value);
      } else {
        params.delete(key);
      }
      router.replace(`/kanban?${params.toString()}`, { scroll: false });
    },
    [searchParams, router]
  );

  const handleProjectChange = useCallback(
    (value: string) => {
      setParam("project", value);
    },
    [setParam]
  );

  const handlePriorityChange = useCallback(
    (value: string) => {
      setParam("priority", value);
    },
    [setParam]
  );

  const handleSearchChange = useCallback(
    (value: string) => {
      setParam("q", value);
    },
    [setParam]
  );

  const handleMyTasksToggle = useCallback(() => {
    setParam("my", filterMyTasks ? "" : "1");
  }, [setParam, filterMyTasks]);

  const handleClearFilters = useCallback(() => {
    router.replace("/kanban", { scroll: false });
  }, [router]);

  /* --- data fetching --- */

  const loadTasks = useCallback(async (wsId: string | null): Promise<void> => {
    try {
      setIsLoading(true);
      setError(null);
      const filters = wsId !== null ? { workspaceId: wsId } : {};
      const data = await fetchTasks(filters);
      setTasks(data);
    } catch (err: unknown) {
      console.error("[Kanban] Failed to fetch tasks:", err);
      setError(
        err instanceof Error
          ? err.message
          : "Something went wrong loading tasks. You could try again when ready."
      );
    } finally {
      setIsLoading(false);
    }
  }, []);

  useEffect(() => {
    if (!workspaceId) {
      setIsLoading(false);
      return;
    }

    const ac = new AbortController();

    async function load(): Promise<void> {
      try {
        setIsLoading(true);
        setError(null);
        const filters: TaskFilters = {};
        if (workspaceId) filters.workspaceId = workspaceId;
        const [taskData, projectData] = await Promise.all([
          fetchTasks(filters),
          fetchProjects(workspaceId ?? undefined),
        ]);
        if (ac.signal.aborted) return;
        setTasks(taskData);
        setProjects(projectData);
      } catch (err: unknown) {
        console.error("[Kanban] Failed to fetch tasks:", err);
        if (ac.signal.aborted) return;
        setError(
          err instanceof Error
            ? err.message
            : "Something went wrong loading tasks. You could try again when ready."
        );
      } finally {
        if (!ac.signal.aborted) {
          setIsLoading(false);
        }
      }
    }

    void load();

    return (): void => {
      ac.abort();
    };
  }, [workspaceId]);

  /* --- apply client-side filters --- */

  const filteredTasks = useMemo(() => {
    let result = tasks;

    if (filterProject) {
      result = result.filter((t) => t.projectId === filterProject);
    }

    if (filterPriority) {
      result = result.filter((t) => t.priority === (filterPriority as TaskPriority));
    }

    if (filterSearch) {
      const q = filterSearch.toLowerCase();
      result = result.filter(
        (t) => t.title.toLowerCase().includes(q) || t.description?.toLowerCase().includes(q)
      );
    }

    if (filterMyTasks) {
      // "My Tasks" filters to tasks assigned to the current user.
      // Since we don't have the current userId readily available,
      // filter by assigneeId being non-null (assigned tasks).
      // A proper implementation would compare against the logged-in user's ID.
      result = result.filter((t) => t.assigneeId !== null);
    }

    return result;
  }, [tasks, filterProject, filterPriority, filterSearch, filterMyTasks]);

  /* --- group tasks by status --- */

  function groupByStatus(allTasks: Task[]): Record<TaskStatus, Task[]> {
    const grouped: Record<TaskStatus, Task[]> = {
      [TaskStatus.NOT_STARTED]: [],
      [TaskStatus.IN_PROGRESS]: [],
      [TaskStatus.PAUSED]: [],
      [TaskStatus.COMPLETED]: [],
      [TaskStatus.ARCHIVED]: [],
    };

    for (const task of allTasks) {
      grouped[task.status].push(task);
    }

    return grouped;
  }

  const grouped = groupByStatus(filteredTasks);

  /* --- drag-and-drop handler --- */

  const handleDragEnd = useCallback(
    (result: DropResult) => {
      const { source, destination, draggableId } = result;

      // Dropped outside a droppable area
      if (!destination) return;

      // Dropped in same position
      if (source.droppableId === destination.droppableId && source.index === destination.index) {
        return;
      }

      const newStatus = destination.droppableId as TaskStatus;
      const taskId = draggableId;

      // Optimistic update: move card in local state
      setTasks((prev) => prev.map((t) => (t.id === taskId ? { ...t, status: newStatus } : t)));

      // Persist to API
      const wsId = workspaceId ?? undefined;
      updateTask(taskId, { status: newStatus }, wsId).catch((err: unknown) => {
        console.error("[Kanban] Failed to update task status:", err);
        // Revert on failure by re-fetching
        void loadTasks(workspaceId);
      });
    },
    [workspaceId, loadTasks]
  );

  /* --- retry handler --- */

  function handleRetry(): void {
    void loadTasks(workspaceId);
  }

  /* --- add task handler --- */

  const handleAddTask = useCallback(
    async (status: TaskStatus, title: string, projectId?: string) => {
      try {
        const wsId = workspaceId ?? undefined;
        const taskData: { title: string; status: TaskStatus; projectId?: string } = {
          title,
          status,
        };
        if (projectId) {
          taskData.projectId = projectId;
        }
        const newTask = await createTask(taskData, wsId);
        // Optimistically add to local state
        setTasks((prev) => [...prev, newTask]);
      } catch (err: unknown) {
        console.error("[Kanban] Failed to create task:", err);
        // Re-fetch on error to get consistent state
        void loadTasks(workspaceId);
      }
    },
    [workspaceId, loadTasks]
  );

  /* --- render --- */

  return (
    <main style={{ padding: "32px 24px", minHeight: "100%" }}>
      {/* Page header */}
      <div style={{ marginBottom: 16 }}>
        <h1
          style={{
            fontSize: "1.875rem",
            fontWeight: 700,
            color: "var(--text)",
            margin: 0,
          }}
        >
          Kanban Board
        </h1>
        <p
          style={{
            fontSize: "0.9rem",
            color: "var(--muted)",
            marginTop: 4,
          }}
        >
          Visualize and manage task progress across stages
        </p>
      </div>

      {/* Filter bar */}
      <FilterBar
        projects={projects}
        projectId={filterProject}
        priority={filterPriority}
        search={filterSearch}
        myTasks={filterMyTasks}
        onProjectChange={handleProjectChange}
        onPriorityChange={handlePriorityChange}
        onSearchChange={handleSearchChange}
        onMyTasksToggle={handleMyTasksToggle}
        onClear={handleClearFilters}
        hasActiveFilters={hasActiveFilters}
      />

      {/* Loading state */}
      {isLoading ? (
        <div className="flex justify-center py-16">
          <MosaicSpinner label="Loading tasks..." />
        </div>
      ) : error !== null ? (
        /* Error state */
        <div
          style={{
            background: "var(--surface)",
            border: "1px solid var(--border)",
            borderRadius: "var(--r-lg)",
            padding: 32,
            textAlign: "center",
          }}
        >
          <p style={{ color: "var(--danger)", margin: "0 0 16px" }}>{error}</p>
          <button
            onClick={handleRetry}
            style={{
              padding: "8px 16px",
              background: "var(--danger)",
              border: "none",
              borderRadius: "var(--r)",
              color: "#fff",
              fontSize: "0.85rem",
              fontWeight: 500,
              cursor: "pointer",
            }}
          >
            Try again
          </button>
        </div>
      ) : filteredTasks.length === 0 && tasks.length > 0 ? (
        /* No results (filtered) */
        <div
          style={{
            background: "var(--surface)",
            border: "1px solid var(--border)",
            borderRadius: "var(--r-lg)",
            padding: 48,
            textAlign: "center",
          }}
        >
          <p style={{ color: "var(--muted)", margin: 0, fontSize: "0.9rem" }}>
            No tasks match your filters.
          </p>
          <button
            type="button"
            onClick={handleClearFilters}
            style={{
              marginTop: 12,
              padding: "6px 14px",
              borderRadius: "var(--r)",
              border: "1px solid var(--border)",
              background: "transparent",
              color: "var(--text-2)",
              fontSize: "0.83rem",
              cursor: "pointer",
            }}
          >
            Clear filters
          </button>
        </div>
      ) : (
        /* Board (always render columns to allow adding first task) */
        <DragDropContext onDragEnd={handleDragEnd}>
          <div
            style={{
              display: "flex",
              gap: 16,
              overflowX: "auto",
              paddingBottom: 16,
              minHeight: 400,
            }}
          >
            {COLUMNS.map((col) => (
              <KanbanColumn
                key={col.status}
                config={col}
                tasks={grouped[col.status]}
                onAddTask={handleAddTask}
                projectId={filterProject}
              />
            ))}
          </div>
        </DragDropContext>
      )}
    </main>
  );
}
