// POST /api/pam/request
//
// Body: { role, durationHours, justification, mfaToken? }
//
// Validates eligibility (the requester's JWT must carry `<role>_eligible`),
// checks the policy, optionally verifies MFA, then either:
//   - `audit` mode: activates the grant immediately + audit-logs.
//   - `manual` mode: writes status='pending' + token, sends approval email.

import { auth } from "@/auth";
import { z } from "zod";
import { prisma } from "@/database/prisma";
import {
  eligibleRoles,
  invalidateAuthzCache,
} from "@/lib/authz";
import {
  generateApprovalToken,
  getPolicy,
  recordAudit,
} from "@/lib/pam";
import { isMailConfigured, sendApprovalEmail } from "@/lib/pam-mail";
import { verifyMfa } from "@/lib/pam-mfa";

export const dynamic = "force-dynamic";

const RequestBody = z.object({
  role: z.string().min(1).max(128),
  durationHours: z.number().int().positive().max(24),
  justification: z.string().min(20).max(1000),
  mfaToken: z.string().optional(),
});

function publicOrigin(req: Request): string {
  return (
    process.env.AUTH_URL ??
    process.env.NEXTAUTH_URL ??
    new URL(req.url).origin
  ).replace(/\/$/, "");
}

export async function POST(req: Request) {
  const session = await auth();
  const user = session?.user as
    | { gscSid?: string; email?: string; displayName?: string; roles?: string[] }
    | undefined;
  const gscsid = user?.gscSid;
  if (!gscsid) {
    return Response.json({ error: "unauthorized" }, { status: 401 });
  }

  let body: z.infer<typeof RequestBody>;
  try {
    body = RequestBody.parse(await req.json());
  } catch (err) {
    return Response.json({ error: "bad_request", detail: String(err) }, { status: 400 });
  }

  // Eligibility — the *_eligible realm role must be in the JWT.
  if (!eligibleRoles({ roles: user.roles ?? [] }).includes(body.role)) {
    await recordAudit({
      event: "denied",
      gscsid: gscsid,
      roleName: body.role,
      detail: { reason: "not_eligible" },
    });
    return Response.json({ error: "not_eligible" }, { status: 403 });
  }

  const policy = await getPolicy(body.role);
  if (!policy) {
    await recordAudit({
      event: "denied",
      gscsid: gscsid,
      roleName: body.role,
      detail: { reason: "no_policy" },
    });
    return Response.json({ error: "no_policy_for_role" }, { status: 404 });
  }

  if (body.durationHours > policy.maxDurationHours) {
    return Response.json(
      {
        error: "duration_exceeds_max",
        maxDurationHours: policy.maxDurationHours,
      },
      { status: 400 },
    );
  }

  // MFA check if policy requires it.
  let mfaEvidence: Record<string, unknown> | undefined;
  if (policy.requiresMfa) {
    const v = await verifyMfa({ gscsid: gscsid, token: body.mfaToken ?? "" });
    if (!v.ok) {
      await recordAudit({
        event: "denied",
        gscsid: gscsid,
        roleName: body.role,
        detail: { reason: "mfa_failed", mfa_reason: v.reason },
      });
      return Response.json({ error: "mfa_failed", detail: v.reason }, { status: 401 });
    }
    mfaEvidence = v.evidence;
  }

  const expiresAt = new Date(Date.now() + body.durationHours * 3600 * 1000);

  // Branch by approval mode.
  if (policy.approvalMode === "audit") {
    // Auto-approve + activate.
    const grant = await prisma.privilegeGrant.create({
      data: {
        gscsid: gscsid,
        roleName: body.role,
        status: "active",
        requestedAt: new Date(),
        grantedAt: new Date(),
        expiresAt,
        grantedBy: null, // self-service
        justification: body.justification,
        mfaEvidence: (mfaEvidence as never) ?? undefined,
      },
      select: { id: true, expiresAt: true, roleName: true },
    });
    await recordAudit({
      event: "requested",
      gscsid: gscsid,
      roleName: body.role,
      grantId: grant.id,
      detail: { durationHours: body.durationHours, justification: body.justification },
    });
    await recordAudit({
      event: "approved-auto",
      gscsid: gscsid,
      roleName: body.role,
      grantId: grant.id,
    });
    await recordAudit({
      event: "activated",
      gscsid: gscsid,
      roleName: body.role,
      grantId: grant.id,
    });
    invalidateAuthzCache(gscsid, body.role);
    return Response.json({
      status: "active",
      grant: { id: grant.id, role: grant.roleName, expiresAt: grant.expiresAt },
    });
  }

  // manual mode — need SMTP + approver_email
  if (!policy.approverEmail) {
    return Response.json({ error: "policy_misconfigured_no_approver" }, { status: 500 });
  }
  if (!isMailConfigured()) {
    return Response.json(
      { error: "mail_not_configured", detail: "PAM_SMTP_HOST is not set; manual-mode requests can't be sent." },
      { status: 503 },
    );
  }

  const token = generateApprovalToken();
  const grant = await prisma.privilegeGrant.create({
    data: {
      gscsid: gscsid,
      roleName: body.role,
      status: "pending",
      approvalToken: token,
      requestedAt: new Date(),
      expiresAt,
      justification: body.justification,
      mfaEvidence: (mfaEvidence as never) ?? undefined,
    },
    select: { id: true, roleName: true },
  });
  await recordAudit({
    event: "requested",
    gscsid: gscsid,
    roleName: body.role,
    grantId: grant.id,
    detail: { durationHours: body.durationHours, justification: body.justification },
  });

  const approveUrl = `${publicOrigin(req)}/api/pam/approve/${encodeURIComponent(token)}`;
  try {
    await sendApprovalEmail({
      to: policy.approverEmail,
      approveUrl,
      requesterDisplay: user.displayName
        ? `${user.displayName} (${user.email ?? gscsid})`
        : (user.email ?? gscsid),
      roleName: body.role,
      durationHours: body.durationHours,
      justification: body.justification,
    });
  } catch (err) {
    return Response.json(
      { error: "mail_send_failed", detail: String(err) },
      { status: 502 },
    );
  }

  return Response.json({
    status: "pending",
    grant: { id: grant.id, role: grant.roleName },
    approverEmail: policy.approverEmail,
  });
}
