import { prisma } from "@/lib/prisma";
import { requireUser, withGuard, HttpError } from "@/lib/guard";
import { parseBody, ok } from "@/lib/http";
import { createTaskSchema } from "@/lib/validators";
import { isManagerTier } from "@/lib/rbac";
import { getIsoWeek } from "@/lib/week";
import { spanAllDepartmentIds, departmentIdFilter } from "@/lib/dept-scope";
import type { Prisma } from "@prisma/client";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

const INCLUDE = {
  user: { select: { id: true, name: true, position: true } },
  contributions: { include: { kpiIndicator: true } },
} satisfies Prisma.TaskInclude;

// GET /api/tasks — list tasks with filters.
// Staff are scoped to their own tasks. Manager-tier may pass ?userId to inspect
// a specific staff member, plus ?weekNumber/&weekYear, ?status, ?channel, ?position.
export const GET = withGuard(async (req: Request) => {
  const me = await requireUser();
  const url = new URL(req.url);
  const qUser = url.searchParams.get("userId");
  const week = url.searchParams.get("weekNumber");
  const weekYear = url.searchParams.get("weekYear");
  const status = url.searchParams.get("status");
  const channel = url.searchParams.get("channel");
  const position = url.searchParams.get("position");
  const departmentId = url.searchParams.get("departmentId");

  const where: Prisma.TaskWhereInput = {};

  if (isManagerTier(me.role)) {
    if (qUser) where.userId = qUser;
    // Filter by the assignee's position and/or department. Cross-cutting (HQ)
    // staff appear under every department filter.
    const userSub: Prisma.UserWhereInput = {};
    if (position) userSub.position = position;
    if (departmentId) {
      const spanIds = await spanAllDepartmentIds();
      userSub.departmentId = departmentIdFilter(departmentId, spanIds);
    }
    if (Object.keys(userSub).length) where.user = userSub;
  } else {
    // Staff: always scoped to self.
    where.userId = me.id;
  }
  if (week) where.weekNumber = Number(week);
  if (weekYear) where.weekYear = Number(weekYear);
  if (status) where.status = status as Prisma.TaskWhereInput["status"];
  if (channel) where.channel = channel as Prisma.TaskWhereInput["channel"];

  const tasks = await prisma.task.findMany({
    where,
    include: INCLUDE,
    orderBy: [{ updatedAt: "desc" }],
  });
  return ok(tasks);
});

// POST /api/tasks — create a task.
// Staff create for themselves. Manager-tier may assign to any staff via userId.
export const POST = withGuard(async (req: Request) => {
  const me = await requireUser();
  const data = await parseBody(req, createTaskSchema);

  let assigneeId = me.id;
  if (data.userId && data.userId !== me.id) {
    if (!isManagerTier(me.role)) {
      throw new HttpError(403, "Only managers can assign tasks to others");
    }
    assigneeId = data.userId;
  }

  const due = data.dueDate ? new Date(data.dueDate) : null;
  const { week, year } = getIsoWeek(due ?? new Date());

  const task = await prisma.task.create({
    data: {
      title: data.title,
      description: data.description ?? null,
      status: data.status ?? "TO_DO",
      priority: data.priority ?? "MEDIUM",
      channel: data.channel ?? null,
      dueDate: due,
      weekNumber: week,
      weekYear: year,
      userId: assigneeId,
      createdById: me.id,
    },
    include: INCLUDE,
  });
  return ok(task, 201);
});
