import { randomUUID } from "node:crypto";
import { NextRequest } from "next/server";
import { BonusStatus, Prisma, Role, UserBonusStatus } from "@prisma/client";
import { z } from "zod";
import { prisma } from "@/server/db";
import { writeAuditLog } from "@/server/audit";
import { fail, ok, parseJson } from "@/server/http";
import { requireUser } from "@/server/security/auth";
import { requireRole } from "@/server/security/rbac";

const grantBonusSchema = z.object({
  userId: z.string().uuid(),
  currency: z.string().min(3).max(8),
  amount: z.coerce.number().positive().max(1000000),
  title: z.string().min(3).max(120).default("Bonus manuel"),
  wagerMultiplier: z.coerce.number().min(0).max(100).default(0),
  terms: z.string().min(8).max(1000),
  expiresAt: z.coerce.date().optional()
});

export async function POST(request: NextRequest) {
  try {
    const auth = await requireUser(request);
    requireRole(auth.roles, [Role.FINANCE_MANAGER, Role.ADMIN, Role.SUPER_ADMIN]);
    const input = await parseJson(request, grantBonusSchema);
    const amount = new Prisma.Decimal(input.amount);
    const wagerMultiplier = new Prisma.Decimal(input.wagerMultiplier);
    const wagerRequired = amount.mul(wagerMultiplier);

    const result = await prisma.$transaction(async (tx) => {
      const user = await tx.user.findUniqueOrThrow({
        where: { id: input.userId },
        include: { profile: true }
      });
      const promotion = await tx.bonusPromotion.create({
        data: {
          code: `ADMIN-${randomUUID()}`,
          name: input.title,
          status: BonusStatus.ACTIVE,
          type: "manual_bonus",
          currency: input.currency,
          maxBonusAmount: amount,
          wageringMultiplier: wagerMultiplier,
          contributionRules: {
            sportsbook: { all: 1 },
            adminGrant: true
          },
          startsAt: new Date(),
          endsAt: input.expiresAt,
          segmentation: {
            userId: user.id,
            email: user.email
          },
          terms: input.terms
        }
      });
      const userBonus = await tx.userBonus.create({
        data: {
          userId: user.id,
          promotionId: promotion.id,
          status: UserBonusStatus.OFFERED,
          bonusAmount: amount,
          wagerRequired,
          remainingAmount: amount,
          expiresAt: input.expiresAt
        },
        include: { promotion: true }
      });

      await writeAuditLog(
        {
          actorUserId: auth.user.id,
          action: "admin.bonus.offer",
          entityType: "UserBonus",
          entityId: userBonus.id,
          after: {
            userId: user.id,
            amount: amount.toFixed(2),
            currency: input.currency,
            wagerMultiplier: wagerMultiplier.toString(),
            wagerRequired: wagerRequired.toFixed(2)
          }
        },
        tx
      );

      return userBonus;
    });

    return ok({ bonus: result });
  } catch (error) {
    return fail(error);
  }
}
