"use client";

import { useMemo, useState, useTransition } from "react";
import { useRouter } from "next/navigation";
import { StatCard } from "@/components/admin/StatCard";
import { AdminEmptyState } from "@/components/admin/AdminEmptyState";
import { TodoItem } from "@/components/admin/TodoItem";
import { NewTodoForm } from "@/components/admin/NewTodoForm";
import { TodoTemplateManager, type TodoTemplateRow } from "@/components/admin/TodoTemplateManager";
import { updateTodoStatusAction, bulkUpdateTodosAction, bulkDeleteTodosAction } from "@/lib/actions/todos";
import { STATUS_LABELS, STATUS_RANK, PRIORITY_RANK } from "@/lib/todoConstants";
import type { TodoStatus, TodoRecurrence } from "@/models/Todo";

const STATUS_ORDER: TodoStatus[] = ["open", "in_progress", "done"];

// Datum -> Fälligkeits-Eimer für die "Nach Fälligkeit"-Ansicht.
function dueBucket(dueIso: string | null, status: TodoStatus): string {
  if (!dueIso) return "Kein Datum";
  const d = new Date(dueIso);
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  const day = new Date(d);
  day.setHours(0, 0, 0, 0);
  const diff = Math.round((day.getTime() - today.getTime()) / 86_400_000);
  if (diff < 0 && status !== "done") return "Überfällig";
  if (diff <= 0) return "Heute";
  if (diff <= 7) return "Diese Woche";
  return "Später";
}
const DUE_BUCKET_ORDER = ["Überfällig", "Heute", "Diese Woche", "Später", "Kein Datum"];

export type StaffOption = { id: string; name: string; avatarPath: string };
export type OrderOption = { id: string; label: string };
export type TodoNote = { id: string; authorId: string; text: string; createdAt: string };
export type TodoSubtask = { id: string; text: string; done: boolean };
export type TodoActivity = { type: string; actorId: string; text: string; createdAt: string };
export type TodoAttachment = { filename: string; storedName: string; size: number; mimeType: string };
export type TodoRow = {
  id: string;
  title: string;
  description: string;
  assignedToId: string;
  additionalAssigneeIds: string[];
  watcherIds: string[];
  createdById: string;
  status: TodoStatus;
  priority: "low" | "normal" | "high";
  dueDate: string | null;
  orderId: string | null;
  labels: string[];
  project: string;
  subtasks: TodoSubtask[];
  attachments: TodoAttachment[];
  activity: TodoActivity[];
  notes: TodoNote[];
  createdAt: string;
  recurrence: TodoRecurrence;
  recurrenceInterval: number;
  recurrenceWeekdays: number[];
  recurrenceEndDate: string | null;
};

function groupsByProject(rows: TodoRow[]): [string, TodoRow[]][] {
  const map = new Map<string, TodoRow[]>();
  for (const r of rows) {
    const key = r.project || "Ohne Projekt";
    (map.get(key) ?? map.set(key, []).get(key)!).push(r);
  }
  return [...map.entries()].sort((a, b) => {
    if (a[0] === "Ohne Projekt") return 1;
    if (b[0] === "Ohne Projekt") return -1;
    return a[0].localeCompare(b[0]);
  });
}

export function TodoBoard({
  initialTodos,
  staffList,
  orderOptions,
  templates,
  allLabels,
  allProjects,
  viewerId,
  canViewAll,
  canCreateForOthers,
  canEditOthers,
  canDeleteOthers,
}: {
  initialTodos: TodoRow[];
  staffList: StaffOption[];
  orderOptions: OrderOption[];
  templates: TodoTemplateRow[];
  allLabels: string[];
  allProjects: string[];
  viewerId: string;
  canViewAll: boolean;
  canCreateForOthers: boolean;
  canEditOthers: boolean;
  canDeleteOthers: boolean;
}) {
  const [scope, setScope] = useState<"mine" | "all">("mine");
  const [statusFilter, setStatusFilter] = useState<"all" | TodoStatus>("all");
  const [assigneeFilter, setAssigneeFilter] = useState<string>("all");
  const [labelFilter, setLabelFilter] = useState<string>("all");
  const [projectFilter, setProjectFilter] = useState<string>("all");
  const [groupByProject, setGroupByProject] = useState(false);
  const [showCreate, setShowCreate] = useState(false);
  const [view, setView] = useState<"list" | "board" | "due">("list");
  const [myDay, setMyDay] = useState(false);
  const [selecting, setSelecting] = useState(false);
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [bulkPending, startBulk] = useTransition();
  const [, startTransition] = useTransition();
  const router = useRouter();

  function toggleSelect(id: string) {
    setSelected((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  }
  function clearSelection() {
    setSelected(new Set());
    setSelecting(false);
  }
  function runBulk(fn: () => Promise<void>) {
    startBulk(async () => {
      await fn();
      router.refresh();
      clearSelection();
    });
  }

  const staffById = useMemo(() => new Map(staffList.map((s) => [s.id, s])), [staffList]);

  const scoped =
    scope === "mine" || myDay
      ? initialTodos.filter((t) => t.assignedToId === viewerId || t.createdById === viewerId)
      : initialTodos;

  const todayIso = new Date().toISOString().slice(0, 10);
  const filtered = scoped.filter((t) => {
    if (statusFilter !== "all" && view !== "board" && t.status !== statusFilter) return false;
    if (scope === "all" && assigneeFilter !== "all" && t.assignedToId !== assigneeFilter) return false;
    if (labelFilter !== "all" && !t.labels.includes(labelFilter)) return false;
    if (projectFilter === "__none__" && t.project) return false;
    if (projectFilter !== "all" && projectFilter !== "__none__" && t.project !== projectFilter) return false;
    if (myDay) {
      if (t.status === "done") return false;
      const due = t.dueDate ? t.dueDate.slice(0, 10) : null;
      if (!(due && due <= todayIso) && t.priority !== "high") return false;
    }
    return true;
  });

  function moveTo(todoId: string, status: TodoStatus) {
    startTransition(async () => {
      await updateTodoStatusAction(todoId, status);
      router.refresh();
    });
  }

  const renderItem = (todo: TodoRow) => {
    const item = (
      <TodoItem
        todo={todo}
        staffById={staffById}
        staffList={staffList}
        orderOptions={orderOptions}
        viewerId={viewerId}
        canCreateForOthers={canCreateForOthers}
        isOwn={todo.assignedToId === viewerId || todo.createdById === viewerId}
        canEditOthers={canEditOthers}
        canDeleteOthers={canDeleteOthers}
      />
    );
    if (!selecting) return <div key={todo.id}>{item}</div>;
    return (
      <div key={todo.id} className="flex items-start gap-2">
        <input
          type="checkbox"
          checked={selected.has(todo.id)}
          onChange={() => toggleSelect(todo.id)}
          className="mt-4 h-4 w-4 shrink-0"
        />
        <div className="min-w-0 flex-1">{item}</div>
      </div>
    );
  };

  const nowIso = new Date().toISOString();
  const sorted = [...filtered].sort((a, b) => {
    if (STATUS_RANK[a.status] !== STATUS_RANK[b.status]) return STATUS_RANK[a.status] - STATUS_RANK[b.status];
    if (PRIORITY_RANK[a.priority] !== PRIORITY_RANK[b.priority]) return PRIORITY_RANK[a.priority] - PRIORITY_RANK[b.priority];
    if (a.dueDate && b.dueDate) return a.dueDate.localeCompare(b.dueDate);
    if (a.dueDate) return -1;
    if (b.dueDate) return 1;
    return b.createdAt.localeCompare(a.createdAt);
  });

  const openCount = scoped.filter((t) => t.status === "open").length;
  const inProgressCount = scoped.filter((t) => t.status === "in_progress").length;
  const doneCount = scoped.filter((t) => t.status === "done").length;
  const overdueCount = scoped.filter((t) => t.status !== "done" && t.dueDate && t.dueDate < nowIso).length;

  return (
    <div>
      <div className="grid grid-cols-2 sm:grid-cols-4 gap-3 mb-6">
        <StatCard label="Offen" value={openCount} />
        <StatCard label="In Bearbeitung" value={inProgressCount} />
        <StatCard label="Überfällig" value={overdueCount} accent={overdueCount ? "red" : "muted"} />
        <StatCard label="Erledigt" value={doneCount} accent="muted" />
      </div>

      <TodoTemplateManager
        templates={templates}
        staffList={staffList}
        viewerId={viewerId}
        canManage={canCreateForOthers}
      />

      <div className="flex flex-wrap items-center gap-3 mb-4">
        <div className="flex border border-white/15 rounded-full p-0.5 text-xs">
          {(["list", "board", "due"] as const).map((v) => (
            <button
              key={v}
              type="button"
              onClick={() => setView(v)}
              className={`rounded-full px-3 py-1.5 transition-colors ${
                view === v ? "bg-white/10 text-[var(--rk-ink)]" : "text-[var(--rk-ink-muted)]"
              }`}
            >
              {v === "list" ? "Liste" : v === "board" ? "Board" : "Fälligkeit"}
            </button>
          ))}
        </div>
        <button
          type="button"
          onClick={() => setMyDay((v) => !v)}
          className={`rounded-full border px-3 py-1.5 text-xs transition-colors ${
            myDay ? "border-[var(--rk-accent)] text-[var(--rk-accent)]" : "border-white/15 text-[var(--rk-ink-muted)] hover:border-white/40"
          }`}
        >
          ☀ Mein Tag
        </button>
        {canViewAll && (
          <div className="flex border border-white/15 rounded-full p-0.5 text-xs">
            <button
              type="button"
              onClick={() => setScope("mine")}
              className={`rounded-full px-3 py-1.5 transition-colors ${
                scope === "mine" ? "bg-white/10 text-[var(--rk-ink)]" : "text-[var(--rk-ink-muted)]"
              }`}
            >
              Meine ToDos
            </button>
            <button
              type="button"
              onClick={() => setScope("all")}
              className={`rounded-full px-3 py-1.5 transition-colors ${
                scope === "all" ? "bg-white/10 text-[var(--rk-ink)]" : "text-[var(--rk-ink-muted)]"
              }`}
            >
              Alle ToDos
            </button>
          </div>
        )}
        <select
          value={statusFilter}
          onChange={(e) => setStatusFilter(e.target.value as "all" | TodoStatus)}
          className="bg-[var(--rk-bg)] border border-white/15 rounded-lg px-2.5 py-1.5 text-xs focus:outline-none focus:border-white/50"
        >
          <option value="all">Alle Status</option>
          {(Object.keys(STATUS_LABELS) as TodoStatus[]).map((s) => (
            <option key={s} value={s}>
              {STATUS_LABELS[s]}
            </option>
          ))}
        </select>
        {scope === "all" && (
          <select
            value={assigneeFilter}
            onChange={(e) => setAssigneeFilter(e.target.value)}
            className="bg-[var(--rk-bg)] border border-white/15 rounded-lg px-2.5 py-1.5 text-xs focus:outline-none focus:border-white/50"
          >
            <option value="all">Alle Mitarbeiter</option>
            {staffList.map((s) => (
              <option key={s.id} value={s.id}>
                {s.name}
              </option>
            ))}
          </select>
        )}
        {allLabels.length > 0 && (
          <select
            value={labelFilter}
            onChange={(e) => setLabelFilter(e.target.value)}
            className="bg-[var(--rk-bg)] border border-white/15 rounded-lg px-2.5 py-1.5 text-xs focus:outline-none focus:border-white/50"
          >
            <option value="all">Alle Labels</option>
            {allLabels.map((l) => (
              <option key={l} value={l}>
                {l}
              </option>
            ))}
          </select>
        )}
        {allProjects.length > 0 && (
          <select
            value={projectFilter}
            onChange={(e) => setProjectFilter(e.target.value)}
            className="bg-[var(--rk-bg)] border border-white/15 rounded-lg px-2.5 py-1.5 text-xs focus:outline-none focus:border-white/50"
          >
            <option value="all">Alle Projekte</option>
            <option value="__none__">Ohne Projekt</option>
            {allProjects.map((p) => (
              <option key={p} value={p}>
                {p}
              </option>
            ))}
          </select>
        )}
        {allProjects.length > 0 && (
          <label className="flex items-center gap-1.5 text-xs text-[var(--rk-ink-muted)]">
            <input
              type="checkbox"
              checked={groupByProject}
              onChange={(e) => setGroupByProject(e.target.checked)}
              className="h-3.5 w-3.5"
            />
            Nach Projekt gruppieren
          </label>
        )}
        <button
          type="button"
          onClick={() => (selecting ? clearSelection() : setSelecting(true))}
          className={`ml-auto text-xs border rounded-lg px-3 py-1.5 transition-colors ${
            selecting ? "border-[var(--rk-accent)] text-[var(--rk-accent)]" : "border-white/30 hover:border-white"
          }`}
        >
          {selecting ? "Auswahl beenden" : "Auswählen"}
        </button>
        <button
          type="button"
          onClick={() => setShowCreate((v) => !v)}
          className="text-xs border border-white/30 rounded-lg px-3.5 py-1.5 hover:border-white transition-colors"
        >
          {showCreate ? "Abbrechen" : "+ Neues ToDo"}
        </button>
      </div>

      {selecting && selected.size > 0 && (
        <div className="sticky top-2 z-30 mb-4 flex flex-wrap items-center gap-2 rounded-xl border border-white/15 bg-[var(--rk-surface)] p-2.5 shadow-[0_16px_40px_-16px_rgba(0,0,0,0.6)]">
          <span className="text-xs text-[var(--rk-ink-muted)]">{selected.size} ausgewählt</span>
          <select
            defaultValue=""
            disabled={bulkPending}
            onChange={(e) => {
              const v = e.target.value;
              e.target.value = "";
              if (v) runBulk(() => bulkUpdateTodosAction([...selected], { status: v }));
            }}
            className="bg-[var(--rk-bg)] border border-white/15 rounded-lg px-2 py-1 text-xs disabled:opacity-50"
          >
            <option value="">Status setzen …</option>
            {STATUS_ORDER.map((s) => (
              <option key={s} value={s}>
                {STATUS_LABELS[s]}
              </option>
            ))}
          </select>
          {canCreateForOthers && (
            <select
              defaultValue=""
              disabled={bulkPending}
              onChange={(e) => {
                const v = e.target.value;
                e.target.value = "";
                if (v) runBulk(() => bulkUpdateTodosAction([...selected], { assigneeId: v }));
              }}
              className="bg-[var(--rk-bg)] border border-white/15 rounded-lg px-2 py-1 text-xs disabled:opacity-50"
            >
              <option value="">Zuständig setzen …</option>
              {staffList.map((s) => (
                <option key={s.id} value={s.id}>
                  {s.name}
                </option>
              ))}
            </select>
          )}
          <label className="flex items-center gap-1 text-xs text-[var(--rk-ink-muted)]">
            Fällig
            <input
              type="date"
              disabled={bulkPending}
              onChange={(e) =>
                runBulk(() => bulkUpdateTodosAction([...selected], { dueDate: e.target.value || null }))
              }
              className="bg-[var(--rk-bg)] border border-white/15 rounded-lg px-1.5 py-1 text-xs [color-scheme:dark] disabled:opacity-50"
            />
          </label>
          <button
            type="button"
            disabled={bulkPending}
            onClick={() => {
              if (confirm(`${selected.size} ToDos wirklich löschen?`))
                runBulk(() => bulkDeleteTodosAction([...selected]));
            }}
            className="text-xs text-red-400/80 hover:text-red-400 disabled:opacity-50"
          >
            Löschen
          </button>
          <button
            type="button"
            onClick={() => setSelected(new Set())}
            className="text-xs text-[var(--rk-ink-muted)] hover:text-[var(--rk-ink)]"
          >
            Auswahl leeren
          </button>
        </div>
      )}

      {showCreate && (
        <div className="mb-4">
          <NewTodoForm
            staffList={staffList}
            orderOptions={orderOptions}
            viewerId={viewerId}
            canCreateForOthers={canCreateForOthers}
            onDone={() => setShowCreate(false)}
          />
        </div>
      )}

      {sorted.length === 0 ? (
        <AdminEmptyState message="Keine ToDos." />
      ) : view === "board" ? (
        <div className="grid gap-3 lg:grid-cols-3">
          {STATUS_ORDER.map((col) => {
            const colTodos = sorted.filter((t) => t.status === col);
            return (
              <div
                key={col}
                onDragOver={(e) => e.preventDefault()}
                onDrop={(e) => {
                  const id = e.dataTransfer.getData("text/todo");
                  if (id) moveTo(id, col);
                }}
                className="rounded-xl border border-white/10 bg-black/10 p-2"
              >
                <p className="px-1 pb-2 text-xs uppercase tracking-[0.12em] text-[var(--rk-ink-muted)]">
                  {STATUS_LABELS[col]} <span className="opacity-60">({colTodos.length})</span>
                </p>
                <div className="flex flex-col gap-2">
                  {colTodos.map((todo) => (
                    <div key={todo.id} draggable onDragStart={(e) => e.dataTransfer.setData("text/todo", todo.id)}>
                      {renderItem(todo)}
                    </div>
                  ))}
                </div>
              </div>
            );
          })}
        </div>
      ) : view === "due" ? (
        <div className="flex flex-col gap-6">
          {DUE_BUCKET_ORDER.map((bucket) => {
            const rows = sorted.filter((t) => dueBucket(t.dueDate, t.status) === bucket);
            if (rows.length === 0) return null;
            return (
              <div key={bucket}>
                <p
                  className={`mb-2 text-xs uppercase tracking-[0.12em] ${
                    bucket === "Überfällig" ? "text-red-400" : "text-[var(--rk-ink-muted)]"
                  }`}
                >
                  {bucket} <span className="opacity-60">({rows.length})</span>
                </p>
                <div className="flex flex-col gap-2">{rows.map(renderItem)}</div>
              </div>
            );
          })}
        </div>
      ) : groupByProject ? (
        <div className="flex flex-col gap-6">
          {groupsByProject(sorted).map(([project, rows]) => (
            <div key={project}>
              <p className="mb-2 text-xs uppercase tracking-[0.12em] text-[var(--rk-ink-muted)]">
                {project} <span className="opacity-60">({rows.length})</span>
              </p>
              <div className="flex flex-col gap-2">{rows.map(renderItem)}</div>
            </div>
          ))}
        </div>
      ) : (
        <div className="flex flex-col gap-2">{sorted.map(renderItem)}</div>
      )}
    </div>
  );
}
