import { prisma } from "@/lib/prisma";
import { requirePermission, withGuard } from "@/lib/guard";
import { ok } from "@/lib/http";
import { progressPct } from "@/lib/utils";
import type { Prisma } from "@prisma/client";
import { spanAllDepartmentIds, departmentIdFilter } from "@/lib/dept-scope";

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

// GET /api/reports — team analytics (Manager-tier). Filters: from, to
// (inclusive YYYY-MM-DD date range), channel, position.
export const GET = withGuard(async (req: Request) => {
  await requirePermission("dashboard:viewTeam");
  const url = new URL(req.url);
  const from = url.searchParams.get("from");
  const to = url.searchParams.get("to");
  const channel = url.searchParams.get("channel");
  const position = url.searchParams.get("position");
  const companyId = url.searchParams.get("companyId");
  const departmentId = url.searchParams.get("departmentId");

  // ── Task filter (drives the staff matrix + breakdowns) ──
  const taskWhere: Prisma.TaskWhereInput = {};
  // Date range filters on the task's due date — the same date its ISO week was
  // derived from — falling back to created_at for tasks that have no due date.
  const fromDate = from ? new Date(`${from}T00:00:00.000Z`) : null;
  const toDate = to ? new Date(`${to}T23:59:59.999Z`) : null;
  if (fromDate || toDate) {
    const range: Prisma.DateTimeFilter = {};
    if (fromDate) range.gte = fromDate;
    if (toDate) range.lte = toDate;
    taskWhere.OR = [{ dueDate: range }, { dueDate: null, createdAt: range }];
  }
  if (channel) taskWhere.channel = channel as Prisma.TaskWhereInput["channel"];

  // Cross-cutting (HQ) departments serve everyone, so they appear under every
  // department/company filter; selecting HQ itself matches only HQ.
  const spanIds = await spanAllDepartmentIds();
  const deptCond = departmentId ? departmentIdFilter(departmentId, spanIds) : undefined;

  // Staff scope drives both the staff list and the task matrix.
  const userScope: Prisma.UserWhereInput = {};
  if (position) userScope.position = position;
  if (deptCond) userScope.departmentId = deptCond;
  if (Object.keys(userScope).length) taskWhere.user = userScope;

  const [users, tasks, deptKpis] = await Promise.all([
    prisma.user.findMany({
      where: { active: true, role: "STAFF", ...userScope },
      select: { id: true, name: true, position: true },
      orderBy: { name: "asc" },
    }),
    prisma.task.findMany({
      where: taskWhere,
      include: { contributions: true, user: { select: { position: true } } },
    }),
    prisma.kpiIndicator.findMany({
      where: {
        type: "DEPARTMENT",
        ...(channel ? { channel: channel as Prisma.KpiIndicatorWhereInput["channel"] } : {}),
        ...(deptCond ? { departmentId: deptCond } : {}),
        ...(companyId
          ? {
              AND: [
                {
                  OR: [
                    { companyId },
                    ...(spanIds.length ? [{ departmentId: { in: spanIds } }] : []),
                  ],
                },
              ],
            }
          : {}),
      },
      orderBy: { name: "asc" },
    }),
  ]);

  // ── Staff matrix: tasks completed vs total KPI delta attributed ──
  const matrix = users.map((u) => {
    const own = tasks.filter((t) => t.userId === u.id);
    const completed = own.filter((t) => t.status === "COMPLETED").length;
    const totalDelta = own.reduce(
      (sum, t) => sum + t.contributions.reduce((s, c) => s + c.metricDelta, 0),
      0
    );
    return {
      id: u.id,
      name: u.name,
      position: u.position,
      tasksTotal: own.length,
      tasksCompleted: completed,
      totalDelta: Math.round(totalDelta * 100) / 100,
    };
  });

  // ── Department KPI progress + weighted team score ──
  const kpiProgress = deptKpis.map((k) => ({
    id: k.id,
    name: k.name,
    unit: k.unit,
    period: k.period,
    channel: k.channel,
    targetValue: k.targetValue,
    currentValue: k.currentValue,
    weightage: k.weightage,
    pct: progressPct(k.currentValue, k.targetValue),
  }));
  const totalWeight = kpiProgress.reduce((s, k) => s + k.weightage, 0);
  const teamScore = totalWeight
    ? Math.round(kpiProgress.reduce((s, k) => s + k.pct * k.weightage, 0) / totalWeight)
    : kpiProgress.length
      ? Math.round(kpiProgress.reduce((s, k) => s + k.pct, 0) / kpiProgress.length)
      : 0;

  // ── Breakdowns ──
  const STATUSES = ["BACKLOG", "TO_DO", "IN_PROGRESS", "REVIEW", "COMPLETED"];
  const statusBreakdown = STATUSES.map((s) => ({
    status: s,
    count: tasks.filter((t) => t.status === s).length,
  }));

  const CHANNELS = ["META", "GOOGLE", "TIKTOK", "OFFLINE", "SEO", "EMAIL", "OTHER"];
  const channelBreakdown = CHANNELS.map((c) => ({
    channel: c,
    count: tasks.filter((t) => t.channel === c).length,
  })).filter((c) => c.count > 0);

  return ok({
    teamScore,
    kpiProgress,
    matrix,
    statusBreakdown,
    channelBreakdown,
    totals: {
      tasks: tasks.length,
      completed: tasks.filter((t) => t.status === "COMPLETED").length,
      staff: users.length,
    },
  });
});
