import { PriorityStatus, Role, TodoStatus } from "@prisma/client";
import prisma from "../prismaClient";
import { buildTodoQuery, ListParams, Requester as QueryRequester } from "./todoQuery";

export type TodoCreateInput = {
  title: string;
  task: string;
  status: TodoStatus;
  priority: PriorityStatus;
  dueDate: Date;
  createdById: string;
  assigneeIds: string[];
};

export type TodoUpdateInput = Partial<{
  title: string;
  task: string;
  status: TodoStatus;
  priority: PriorityStatus;
  dueDate: Date | null;
  assigneeIds: string[];
}>;

export async function createTodo(data: TodoCreateInput) {
  const todo = await prisma.todo.create({
    data: {
      title: data.title,
      task: data.task,
      status: data.status,
      priority: data.priority,
      dueDate: data.dueDate,
      createdBy: { connect: { id: data.createdById } },
      assignees: { connect: data.assigneeIds.map((id) => ({ id })) },
    },
    include: { assignees: true, createdBy: true },
  });
  return todo;
}

export async function updateTodo(todoId: string, data: TodoUpdateInput) {
  const todo = await prisma.todo.update({
    where: { id: todoId },
    data: {
      ...(data.title !== undefined ? { title: data.title } : {}),
      ...(data.task !== undefined ? { task: data.task } : {}),
      ...(data.status !== undefined ? { status: data.status } : {}),
      ...(data.priority !== undefined ? { priority: data.priority } : {}),
      ...(data.dueDate !== undefined ? { dueDate: data.dueDate ?? undefined } : {}),
      ...(data.assigneeIds !== undefined
        ? { assignees: { set: data.assigneeIds.map((id) => ({ id })) } }
        : {}),
    },
    include: { assignees: true, createdBy: true },
  });
  return todo;
}

export async function deleteTodo(todoId: string) {
  await prisma.todo.delete({ where: { id: todoId } });
}

export async function listTodos(params: ListParams, requester: QueryRequester) {
  const { page, limit, where, orderBy, skip, take } = buildTodoQuery(params, requester);
  const [total, items] = await Promise.all([
    prisma.todo.count({ where }),
    prisma.todo.findMany({ where, include: { assignees: true, createdBy: true }, orderBy, skip, take }),
  ]);
  return { items, total, page, limit } as const;
}

export async function getTodoAccessShape(todoId: string) {
  return prisma.todo.findUnique({
    where: { id: todoId },
    include: {
      assignees: { select: { id: true, managerId: true } },
      createdBy: { select: { id: true } },
    },
  });
}

export async function listComments(todoId: string) {
  return prisma.comment.findMany({
    where: { todoId },
    include: {
      user: { select: { id: true, firstName: true, lastName: true, imageUrl: true, role: true } },
    },
    orderBy: { createdAt: "asc" },
  });
}

export async function addComment(todoId: string, userId: string, content: string) {
  return prisma.comment.create({
    data: {
      content,
      todo: { connect: { id: todoId } },
      user: { connect: { id: userId } },
    },
    include: {
      user: { select: { id: true, firstName: true, lastName: true, imageUrl: true, role: true } },
    },
  });
}

export async function getCommentSlim(commentId: string) {
  return prisma.comment.findUnique({
    where: { id: commentId },
    select: { id: true, userId: true, todoId: true },
  });
}

export async function updateComment(commentId: string, content: string) {
  return prisma.comment.update({
    where: { id: commentId },
    data: { content },
    include: {
      user: { select: { id: true, firstName: true, lastName: true, imageUrl: true, role: true } },
    },
  });
}

export async function deleteComment(commentId: string) {
  await prisma.comment.delete({ where: { id: commentId } });
}

export async function getTodosForUser(targetUserId: string, requester: { id: string; role: Role }) {
  // Determine target user's role for Manager override
  const targetUser = await prisma.user.findUnique({ where: { id: targetUserId }, select: { role: true } });

  let visibilityClause: any = {};
  if (requester.role === Role.MANAGER) {
    if (targetUser?.role === Role.ADMIN) {
      // Managers can view ANY Admin's todos (admin detail view use-case)
      visibilityClause = {};
    } else {
      visibilityClause = {
        OR: [
          { assignees: { some: { id: requester.id } } },
          { assignees: { some: { managerId: requester.id } } },
        ],
      } as any;
    }
  } else if (requester.role === Role.ADMIN) {
    visibilityClause = { assignees: { some: { id: requester.id } } } as any;
  }

  const todos = await prisma.todo.findMany({
    where: { AND: [{ assignees: { some: { id: targetUserId } } }, visibilityClause] },
    include: { assignees: true, createdBy: true },
  });
  return todos;
}
