import { NextRequest } from "next/server";
import { BonusStatus, Role } from "@prisma/client";
import { z } from "zod";
import { prisma } from "@/server/db";
import { AppError } from "@/server/errors";
import { fail, ok, parseJson } from "@/server/http";
import { requireUser } from "@/server/security/auth";
import { requireRole } from "@/server/security/rbac";
import { normalizePromotionCode, serializeWelcomePromotion, WELCOME_PROMO_TYPE } from "@/server/bonus/welcome";

const upsertPromotionSchema = z.object({
  code: z.string().min(2).max(40),
  name: z.string().min(3).max(120),
  status: z.nativeEnum(BonusStatus).default(BonusStatus.ACTIVE),
  matchPercent: z.coerce.number().min(0).max(1000),
  maxBonusAmount: z.coerce.number().positive().max(1000000),
  wageringMultiplier: z.coerce.number().min(0).max(100),
  terms: z.string().min(8).max(1200),
  endsAt: z.coerce.date().nullable().optional()
});

export const dynamic = "force-dynamic";

export async function GET(request: NextRequest) {
  try {
    const auth = await requireUser(request);
    requireRole(auth.roles, [Role.ADMIN, Role.SUPER_ADMIN]);

    const promotions = await prisma.bonusPromotion.findMany({
      where: { type: WELCOME_PROMO_TYPE, status: { not: BonusStatus.ARCHIVED } },
      orderBy: [{ code: "asc" }]
    });

    return ok({ promotions: promotions.map(serializeWelcomePromotion) });
  } catch (error) {
    return fail(error);
  }
}

export async function POST(request: NextRequest) {
  try {
    const auth = await requireUser(request);
    requireRole(auth.roles, [Role.ADMIN, Role.SUPER_ADMIN]);
    const input = await parseJson(request, upsertPromotionSchema);
    const code = normalizePromotionCode(input.code);

    const promotion = await prisma.bonusPromotion.upsert({
      where: { code },
      create: {
        code,
        name: input.name,
        status: input.status,
        type: WELCOME_PROMO_TYPE,
        currency: "EUR",
        maxBonusAmount: input.maxBonusAmount,
        wageringMultiplier: input.wageringMultiplier,
        contributionRules: welcomeRules(input.matchPercent, code !== "WELCOME_SPORT"),
        startsAt: new Date(),
        endsAt: input.endsAt ?? undefined,
        terms: input.terms
      },
      update: {
        name: input.name,
        status: input.status,
        maxBonusAmount: input.maxBonusAmount,
        wageringMultiplier: input.wageringMultiplier,
        contributionRules: welcomeRules(input.matchPercent, code !== "WELCOME_SPORT"),
        endsAt: input.endsAt ?? null,
        terms: input.terms
      }
    });

    return ok({ promotion: serializeWelcomePromotion(promotion) });
  } catch (error) {
    return fail(error);
  }
}

export async function DELETE(request: NextRequest) {
  try {
    const auth = await requireUser(request);
    requireRole(auth.roles, [Role.ADMIN, Role.SUPER_ADMIN]);

    const code = normalizePromotionCode(request.nextUrl.searchParams.get("code") ?? "");
    if (!code) {
      throw new AppError("Promotion code is required", 422, "PROMOTION_CODE_REQUIRED");
    }
    if (code === "WELCOME_SPORT") {
      throw new AppError("L'offre Sport se modifie mais ne se supprime pas.", 422, "SPORT_PROMOTION_PROTECTED");
    }

    const result = await prisma.bonusPromotion.updateMany({
      where: { code, type: WELCOME_PROMO_TYPE },
      data: { status: BonusStatus.ARCHIVED }
    });

    if (result.count === 0) {
      throw new AppError("Code promotionnel introuvable", 404, "PROMOTION_NOT_FOUND");
    }

    return ok({ code });
  } catch (error) {
    return fail(error);
  }
}

function welcomeRules(matchPercent: number, promoCode: boolean) {
  return {
    welcome: {
      matchPercent,
      firstDepositOnly: true,
      promoCode
    },
    sportsbook: { all: 1 }
  };
}
