import { prisma } from './db.js';
import { clearDropFeed } from './feed.js';
import { getIO } from './realtime.js';

/**
 * Player progress wiped on server prestige.
 * Kept: username, password, avatar, bio, role, createdAt (Joined),
 * playTimeSeconds, lastConnection, achievements,
 * and lifetime stats via transactions open_case / jackpot_win.
 */
export const PLAYER_PROGRESS_RESET = {
  balance: '0',
  osuBalance: 0,
  prBalance: '0',
  lastAdAt: null,
  autoSellEnabled: false,
  autoSellThresholdCents: '1000',
  prestigeCount: 0,
  prestigeChanceBonus: 0,
  prestigeGainBonus: 0,
  prestigeWearBonus: 0,
  prestigePrBonus: 0,
  prestigeOpenBonus: 0,
  prestigeQualityBonus: 0,
  prestigeAnimReduction: 0,
  prestigeRefundChance: 0,
  prestigeRespinChance: 0,
  prestigeVaultSlots: 0,
  prestigeOfflineYield: 0,
  prestigeOnlineYield: 0,
  vaultYieldAt: null,
};

/** Transaction types that back profile lifetime stats — never wiped. */
export const STATS_TRANSACTION_TYPES = ['open_case', 'jackpot_win'];

export function slugifyAchievementKey(raw) {
  const s = String(raw || '')
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '_')
    .replace(/^_|_$/g, '')
    .slice(0, 48);
  return s || `server_prestige_${Date.now()}`;
}

/**
 * Wipe non-admin economy / prestige progress.
 * Preserves identity, presence stats, achievements, and lifetime win/open logs.
 */
export async function runServerPrestige({
  achievementKey,
  achievementName,
  achievementDescription,
  achievementIcon = '♛',
}) {
  const key = slugifyAchievementKey(achievementKey);
  const name = String(achievementName || '').trim().slice(0, 80);
  const description = String(achievementDescription || '').trim().slice(0, 240);
  const icon = String(achievementIcon || '♛').trim().slice(0, 8) || '♛';

  if (!name) {
    const err = new Error('Achievement name is required');
    err.status = 400;
    throw err;
  }
  if (!description) {
    const err = new Error('Achievement description is required');
    err.status = 400;
    throw err;
  }

  const result = await prisma.$transaction(
    async (tx) => {
      const players = await tx.user.findMany({
        where: { role: { not: 'admin' } },
        select: { id: true },
      });
      const ids = players.map((p) => p.id);

      // Active battle pots / locks (inventory FKs)
      await tx.jackpotDeposit.deleteMany({});
      await tx.jackpotRound.deleteMany({});

      if (ids.length) {
        await tx.prestigeLog.deleteMany({ where: { userId: { in: ids } } });
        await tx.catalogEntry.deleteMany({ where: { userId: { in: ids } } });
        await tx.caseKeyProgress.deleteMany({ where: { userId: { in: ids } } });
        // Keep open_case / jackpot_win for profile stats
        await tx.transaction.deleteMany({
          where: {
            userId: { in: ids },
            type: { notIn: STATS_TRANSACTION_TYPES },
          },
        });
        await tx.inventoryItem.deleteMany({ where: { userId: { in: ids } } });
        await tx.user.updateMany({
          where: { id: { in: ids } },
          data: PLAYER_PROGRESS_RESET,
        });
      }

      const maxOrder = await tx.achievement.aggregate({ _max: { sortOrder: true } });
      const sortOrder = (maxOrder._max.sortOrder ?? 0) + 1;

      const achievement = await tx.achievement.upsert({
        where: { key },
        create: { key, name, description, icon, sortOrder },
        update: { name, description, icon },
      });

      if (ids.length) {
        const already = await tx.userAchievement.findMany({
          where: { userId: { in: ids }, achievementId: achievement.id },
          select: { userId: true },
        });
        const have = new Set(already.map((r) => r.userId));
        const missing = ids.filter((userId) => !have.has(userId));
        if (missing.length) {
          await tx.userAchievement.createMany({
            data: missing.map((userId) => ({
              userId,
              achievementId: achievement.id,
            })),
          });
        }
      }

      return {
        playersReset: ids.length,
        achievement: {
          id: achievement.id,
          key: achievement.key,
          name: achievement.name,
          description: achievement.description,
          icon: achievement.icon,
        },
      };
    },
    { timeout: 120_000, maxWait: 20_000 }
  );

  clearDropFeed();

  const io = getIO();
  if (io) {
    io.emit('server:prestige-reset', {
      at: new Date().toISOString(),
      achievement: result.achievement,
      playersReset: result.playersReset,
    });
  }

  return result;
}
