import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireRole } from "@/lib/auth";
import { addMonths } from "@/lib/utils";
import { BillingCycle, PATTERN_BY_ID, estimateCost, tierRangeLabel, yearlyEffectiveMonthly } from "@/lib/pricing";
import { getReferralCommissionPct, getReferralDiscountPct } from "@/lib/referral";

type Params = { params: Promise<{ id: string }> };

/** Approve or reject a package request. Approving creates a subscription. */
export async function PATCH(req: Request, { params }: Params) {
  const session = await requireRole("SUPER_ADMIN");
  if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

  const { id } = await params;
  const requestId = Number(id);
  const body = await req.json().catch(() => ({}));
  const action = String(body.action ?? "");

  if (!["approve", "reject"].includes(action)) {
    return NextResponse.json({ error: "Invalid action" }, { status: 400 });
  }

  const request = await prisma.packageRequest.findUnique({
    where: { id: requestId },
    include: { packagePlan: true, pricingTier: true, subscription: true },
  });

  if (!request) {
    return NextResponse.json({ error: "Request not found" }, { status: 404 });
  }
  if (request.status !== "PENDING") {
    return NextResponse.json({ error: "Request already decided" }, { status: 409 });
  }

  if (action === "reject") {
    const updated = await prisma.packageRequest.update({
      where: { id: requestId },
      data: { status: "REJECTED", decidedAt: new Date() },
    });
    return NextResponse.json({ request: updated });
  }

  // Approve → create subscription in a transaction
  try {
    const result = await prisma.$transaction(async (tx) => {
      const now = new Date();
      let totalAmount = request.packagePlan
        ? (request.packagePlan.price as unknown as number)
        : 0;
      let months = request.packagePlan?.durationMonths ?? 1;
      let breakdown: ReturnType<typeof estimateCost> | null = null;
      let tierId: number | null = null;
      let rangeLabel: string | null = null;

      if (request.pricingTierId && request.pricingTier) {
        // slab pricing: flat monthly price per student range; yearly takes
        // the tier's discount; the one-time setup fee applies to the first
        const tier = request.pricingTier;
        const cycle = (request.billingCycle === "YEARLY" ? "YEARLY" : "MONTHLY") as BillingCycle;
        const priorSubs = await tx.subscription.count({
          where: { institutionId: request.institutionId },
        });
        const monthly = Number(tier.monthlyPrice);
        totalAmount =
          cycle === "YEARLY"
            ? yearlyEffectiveMonthly(monthly, Number(tier.yearlyDiscount)) * 12
            : monthly;
        if (priorSubs === 0) totalAmount += 5000; // one-time setup fee
        totalAmount = Math.round(totalAmount * 100) / 100;
        months = cycle === "YEARLY" ? 12 : 1;
        tierId = tier.id;
        rangeLabel = tierRangeLabel(tier.minStudents, tier.maxStudents);
      } else if (request.packagePlan?.educationPattern) {
        // education-pattern pricing: rate × students × cycle (+ setup fee for
        // the first subscription); legacy plans keep their fixed price
        const pattern = PATTERN_BY_ID[request.packagePlan.educationPattern];
        if (pattern) {
          const cycle = (request.billingCycle === "YEARLY" ? "YEARLY" : "MONTHLY") as BillingCycle;
          const students =
            request.studentCount ??
            (await tx.student.count({
              where: { institutionId: request.institutionId, status: "ACTIVE" },
            }));
          const priorSubs = await tx.subscription.count({
            where: { institutionId: request.institutionId },
          });
          const cost = estimateCost({
            pattern,
            students,
            cycle,
            withSetup: priorSubs === 0,
          });
          totalAmount = cost.total as unknown as number;
          months = cost.months;
          breakdown = cost;
        }
      }

      // Referral benefit: an institution that registered with a subscriber's
      // referral code gets the platform's referral discount (central-admin
      // set) once — on the first subscription approved after registering.
      let referralDiscount: { pct: number; amount: number } | null = null;
      const referred = await tx.institution.findUnique({
        where: { id: request.institutionId },
        select: { referredById: true, referralDiscountAppliedAt: true },
      });
      if (referred?.referredById && !referred.referralDiscountAppliedAt) {
        const pct = await getReferralDiscountPct();
        if (pct > 0 && totalAmount > 0) {
          const amount = Math.round(totalAmount * (pct / 100) * 100) / 100;
          if (amount > 0) {
            totalAmount = Math.round((totalAmount - amount) * 100) / 100;
            referralDiscount = { pct, amount };
            await tx.institution.update({
              where: { id: request.institutionId },
              data: { referralDiscountAppliedAt: now },
            });
          }
        }
      }

      const subscription = await tx.subscription.create({
        data: {
          institutionId: request.institutionId,
          packagePlanId: request.packagePlanId,
          requestId: request.id,
          pricingTierId: tierId,
          studentRange: rangeLabel,
          startDate: now,
          endDate: addMonths(now, months),
          totalAmount,
          status: "ACTIVE",
        },
      });

      // Referral commission (the code OWNER's side of the deal): every time
      // a referred institution takes a YEARLY subscription, the owner of the
      // used code earns the platform's commission % of that total yearly
      // amount. Recorded in the referral_commissions ledger — payouts are
      // handled out-of-band by the central team.
      let referralCommission: { pct: number; amount: number; ownerName: string | null } | null = null;
      const wasYearly = request.billingCycle === "YEARLY";
      if (referred?.referredById && wasYearly && totalAmount > 0) {
        const commissionPct = await getReferralCommissionPct();
        const commissionAmount =
          commissionPct > 0 ? Math.round(totalAmount * (commissionPct / 100) * 100) / 100 : 0;
        if (commissionAmount > 0) {
          const owner = await tx.institution.findUnique({
            where: { id: referred.referredById },
            select: { id: true, name: true, status: true },
          });
          // only codes of still-active subscribers keep earning
          if (owner && owner.status === "ACTIVE") {
            await tx.referralCommission.create({
              data: {
                ownerInstitutionId: owner.id,
                buyerInstitutionId: request.institutionId,
                subscriptionId: subscription.id,
                pct: commissionPct,
                amount: commissionAmount,
              },
            });
            referralCommission = { pct: commissionPct, amount: commissionAmount, ownerName: owner.name };
          }
        }
      }

      const updated = await tx.packageRequest.update({
        where: { id: requestId },
        data: { status: "APPROVED", decidedAt: now },
      });
      return { subscription, request: updated, breakdown, referralDiscount, referralCommission };
    });
    return NextResponse.json(result);
  } catch {
    return NextResponse.json({ error: "Could not approve request" }, { status: 500 });
  }
}
