import "server-only";
import { prisma } from "@/lib/prisma";
import type { Priority } from "@prisma/client";

export type AssigneeDTO = { id: string; name: string; avatarUrl: string | null };

export type TaskDTO = {
  id: string;
  columnId: string;
  title: string;
  description: string | null;
  priority: Priority;
  deadline: string | null;
  position: number;
  color: string | null;
  assignees: AssigneeDTO[];
  projectId: string | null;
  projectName: string | null;
  labels: { id: string; name: string; color: string }[];
  commentCount: number;
  checklist: { done: number; total: number };
};

export type ColumnDTO = {
  id: string;
  key: string;
  name: string;
  color: string | null;
  tasks: TaskDTO[];
};

export type BoardDTO = {
  id: string;
  name: string;
  icon: string | null;
  color: string | null;
  adminId: string | null;
  adminName: string | null;
  columns: ColumnDTO[];
};
export type BoardListItem = {
  id: string;
  name: string;
  icon: string | null;
  color: string | null;
  isDefault: boolean;
};

/** Zählt Checklisten-Punkte (`- [ ]` / `- [x]`) in der Beschreibung. */
export function parseChecklist(desc: string | null): { done: number; total: number } {
  if (!desc) return { done: 0, total: 0 };
  let done = 0;
  let total = 0;
  for (const line of desc.split("\n")) {
    const m = line.match(/^\s*[-*]\s*\[( |x|X)\]/);
    if (m) {
      total += 1;
      if (m[1].toLowerCase() === "x") done += 1;
    }
  }
  return { done, total };
}

const taskSelect = {
  id: true,
  columnId: true,
  title: true,
  description: true,
  priority: true,
  deadline: true,
  position: true,
  color: true,
  projectId: true,
  project: { select: { name: true } },
  assignees: {
    select: { user: { select: { id: true, name: true, displayName: true, avatarUrl: true } } },
  },
  labels: { select: { label: { select: { id: true, name: true, color: true } } } },
  _count: { select: { comments: true } },
} as const;

type TaskRow = {
  id: string;
  columnId: string;
  title: string;
  description: string | null;
  priority: Priority;
  deadline: Date | null;
  position: number;
  color: string | null;
  projectId: string | null;
  project: { name: string } | null;
  assignees: { user: { id: string; name: string; displayName: string | null; avatarUrl: string | null } }[];
  labels: { label: { id: string; name: string; color: string } }[];
  _count: { comments: number };
};

function mapTask(t: TaskRow): TaskDTO {
  return {
    id: t.id,
    columnId: t.columnId,
    title: t.title,
    description: t.description,
    priority: t.priority,
    deadline: t.deadline ? t.deadline.toISOString() : null,
    position: t.position,
    color: t.color,
    assignees: t.assignees.map((a) => ({
      id: a.user.id,
      name: a.user.displayName ?? a.user.name,
      avatarUrl: a.user.avatarUrl,
    })),
    projectId: t.projectId,
    projectName: t.project?.name ?? null,
    labels: t.labels.map((l) => l.label),
    commentCount: t._count.comments,
    checklist: parseChecklist(t.description),
  };
}

/**
 * Sichtbarkeits-Filter: Standard-/globale Boards (ohne Team) plus Boards der
 * Teams, in denen der Nutzer Mitglied ist. Ohne userId → alle Boards (Admin).
 */
function boardVisibilityWhere(userId?: string) {
  if (!userId) return {};
  return {
    OR: [
      // Globales Board: keinem Team zugeordnet → für alle sichtbar.
      { teams: { none: {} } },
      // Team-Board: sichtbar, wenn man Mitglied eines zugeordneten Teams ist.
      { teams: { some: { team: { members: { some: { userId } } } } } },
    ],
  };
}

/** Liste der für den Nutzer verfügbaren Boards (für den Board-Wechsler). */
export async function getBoards(userId?: string): Promise<BoardListItem[]> {
  const boards = await prisma.board.findMany({
    where: boardVisibilityWhere(userId),
    orderBy: [{ isDefault: "desc" }, { createdAt: "asc" }],
    select: { id: true, name: true, icon: true, color: true, isDefault: true },
  });
  return boards;
}

/** Lädt ein Board (per ID oder Standard) mit Spalten & Aufgaben. */
export async function getBoard(boardId?: string, userId?: string): Promise<BoardDTO | null> {
  const board = await prisma.board.findFirst({
    where: boardId ? { id: boardId, ...boardVisibilityWhere(userId) } : { isDefault: true },
    select: {
      id: true,
      name: true,
      icon: true,
      color: true,
      adminId: true,
      admin: { select: { name: true, displayName: true } },
      columns: {
        orderBy: { position: "asc" },
        select: {
          id: true,
          key: true,
          name: true,
          color: true,
          tasks: { where: { archivedAt: null }, orderBy: { position: "asc" }, select: taskSelect },
        },
      },
    },
  });
  if (!board) {
    if (boardId) return getBoard(undefined, userId); // Fallback auf Standard-Board
    return null;
  }
  return {
    id: board.id,
    name: board.name,
    icon: board.icon,
    color: board.color,
    adminId: board.adminId,
    adminName: board.admin ? board.admin.displayName ?? board.admin.name : null,
    columns: board.columns.map((c) => ({
      id: c.id,
      key: c.key,
      name: c.name,
      color: c.color,
      tasks: c.tasks.map(mapTask),
    })),
  };
}

export async function getTaskById(taskId: string): Promise<TaskDTO | null> {
  const t = await prisma.task.findUnique({ where: { id: taskId }, select: taskSelect });
  return t ? mapTask(t) : null;
}

export async function getBoardOptions() {
  const [users, projects, labels] = await Promise.all([
    prisma.user.findMany({
      where: { status: "ACTIVE" },
      orderBy: { name: "asc" },
      select: { id: true, name: true, displayName: true, avatarUrl: true },
    }),
    prisma.project.findMany({ orderBy: { name: "asc" }, select: { id: true, name: true } }),
    prisma.label.findMany({ orderBy: { name: "asc" }, select: { id: true, name: true, color: true } }),
  ]);
  return {
    users: users.map((u) => ({ id: u.id, name: u.displayName ?? u.name, avatarUrl: u.avatarUrl })),
    projects,
    labels,
  };
}

export type TaskCommentDTO = {
  id: string;
  body: string;
  authorId: string;
  authorName: string;
  authorAvatar: string | null;
  createdAt: string;
};

export async function getTaskComments(taskId: string): Promise<TaskCommentDTO[]> {
  const rows = await prisma.taskComment.findMany({
    where: { taskId },
    orderBy: { createdAt: "asc" },
    select: {
      id: true,
      body: true,
      authorId: true,
      createdAt: true,
      author: { select: { name: true, displayName: true, avatarUrl: true } },
    },
  });
  return rows.map((r) => ({
    id: r.id,
    body: r.body,
    authorId: r.authorId,
    authorName: r.author.displayName ?? r.author.name,
    authorAvatar: r.author.avatarUrl,
    createdAt: r.createdAt.toISOString(),
  }));
}
