import { prisma } from "@/lib/prisma";
import { requireUser, withGuard, HttpError } from "@/lib/guard";
import { parseBody, ok } from "@/lib/http";
import { contributionSchema } from "@/lib/validators";
import { isManagerTier } from "@/lib/rbac";
import { startOfIsoWeek } from "@/lib/week";

export const runtime = "nodejs";

// POST /api/contributions — link a task to a KPI indicator and add its metric
// delta to that KPI. The delta feeds BOTH the KPI's legacy live current value
// AND the actual value for the task's calendar month (so Dashboard rings and
// the Monthly Report update automatically from logged tasks).
export const POST = withGuard(async (req: Request) => {
  const me = await requireUser();
  const data = await parseBody(req, contributionSchema);

  const task = await prisma.task.findUnique({ where: { id: data.taskId } });
  if (!task) throw new HttpError(404, "Task not found");
  if (!isManagerTier(me.role) && task.userId !== me.id) {
    throw new HttpError(403, "You can only log contributions for your own tasks");
  }

  const kpi = await prisma.kpiIndicator.findUnique({
    where: { id: data.kpiIndicatorId },
  });
  if (!kpi) throw new HttpError(404, "KPI indicator not found");

  // The month this contribution counts toward: the task's due date, falling
  // back to the Monday of its ISO week (weekNumber/weekYear are always set).
  const basis = task.dueDate ?? startOfIsoWeek(task.weekNumber, task.weekYear);
  const year = basis.getUTCFullYear();
  const month = basis.getUTCMonth() + 1;

  const [log] = await prisma.$transaction([
    prisma.taskContributionLog.create({
      data: {
        taskId: data.taskId,
        kpiIndicatorId: data.kpiIndicatorId,
        impactDescription: data.impactDescription ?? null,
        metricDelta: data.metricDelta,
        year,
        month,
      },
      include: { kpiIndicator: true },
    }),
    prisma.kpiIndicator.update({
      where: { id: data.kpiIndicatorId },
      data: { currentValue: { increment: data.metricDelta } },
    }),
    // Add the delta to that KPI's actual for the month (creating the monthly
    // row on first contribution).
    prisma.kpiMonthlyValue.upsert({
      where: {
        kpiIndicatorId_year_month: {
          kpiIndicatorId: data.kpiIndicatorId,
          year,
          month,
        },
      },
      create: {
        kpiIndicatorId: data.kpiIndicatorId,
        year,
        month,
        actualValue: data.metricDelta,
      },
      update: { actualValue: { increment: data.metricDelta } },
    }),
  ]);
  return ok(log, 201);
});
