import { NextRequest } from "next/server";
import { Prisma, Role, UserStatus, WalletAccountType } from "@prisma/client";
import { z } from "zod";
import { prisma } from "@/server/db";
import { fail, ok, parseJson } from "@/server/http";
import { requireUser } from "@/server/security/auth";
import { requireRole } from "@/server/security/rbac";
import { writeAuditLog } from "@/server/audit";

const patchSchema = z.object({
  userId: z.string().uuid(),
  status: z.nativeEnum(UserStatus).optional(),
  roles: z.array(z.nativeEnum(Role)).optional()
});

export const dynamic = "force-dynamic";

export async function GET(request: NextRequest) {
  try {
    const { roles } = await requireUser(request);
    requireRole(roles, [Role.ADMIN, Role.SUPPORT, Role.KYC_ANALYST, Role.RISK_ANALYST, Role.FINANCE_MANAGER]);
    const users = await prisma.user.findMany({
      include: {
        profile: true,
        vipProgress: true,
        wallets: { include: { accounts: true } },
        kycCases: { orderBy: { openedAt: "desc" }, take: 1 },
        _count: {
          select: {
            betTickets: true,
            withdrawalRequests: true,
            riskEvents: true,
            subjectNotes: true
          }
        }
      },
      orderBy: { createdAt: "desc" },
      take: 100
    });
    return ok({
      users: users.map((user) => ({
        id: user.id,
        email: user.email,
        username: user.username,
        status: user.status,
        roles: user.roles,
        country: user.profile?.country,
        currency: user.profile?.currency ?? user.wallets[0]?.currency ?? "EUR",
        createdAt: user.createdAt,
        lastLoginAt: user.lastLoginAt,
        kycStatus: user.kycCases[0]?.status ?? "NOT_STARTED",
        vipTier: user.vipProgress?.tierKey,
        availableBalance: money(balance(user, WalletAccountType.AVAILABLE)),
        bonusBalance: money(balance(user, WalletAccountType.BONUS)),
        tickets: user._count.betTickets,
        withdrawals: user._count.withdrawalRequests,
        riskEvents: user._count.riskEvents,
        notes: user._count.subjectNotes
      }))
    });
  } catch (error) {
    return fail(error);
  }
}

function balance(
  user: Awaited<ReturnType<typeof prisma.user.findMany>>[number] & {
    wallets: { accounts: { type: WalletAccountType; balance: Prisma.Decimal }[] }[];
  },
  type: WalletAccountType
) {
  return user.wallets
    .flatMap((wallet) => wallet.accounts)
    .filter((account) => account.type === type)
    .reduce((total, account) => total.plus(account.balance), new Prisma.Decimal(0));
}

function money(value: Prisma.Decimal | number | string | null | undefined) {
  return new Prisma.Decimal(value ?? 0).toFixed(2);
}

export async function PATCH(request: NextRequest) {
  try {
    const auth = await requireUser(request);
    requireRole(auth.roles, [Role.ADMIN, Role.SUPER_ADMIN]);
    const input = await parseJson(request, patchSchema);
    const before = await prisma.user.findUniqueOrThrow({ where: { id: input.userId } });
    const after = await prisma.user.update({
      where: { id: input.userId },
      data: {
        status: input.status,
        roles: input.roles
      }
    });
    await writeAuditLog({
      actorUserId: auth.user.id,
      action: "admin.user.update",
      entityType: "User",
      entityId: after.id,
      before: { status: before.status, roles: before.roles },
      after: { status: after.status, roles: after.roles }
    });
    return ok({ user: after });
  } catch (error) {
    return fail(error);
  }
}
