/**
 * Debug Handlers
 * Development-only helpers for deep links, test presets, and resource grants.
 */

import { config } from '../config.js';
import type { PlayerSession } from '../game/PlayerSession.js';
import { getPeakEnergy } from '../stats/stats_manager.js';
import { modifyStat, setStat } from '../utils/statUtils.js';
import { resolvePayloadField, resolvePayloadId, resolvePayloadNumber } from './payloadHelpers.js';

type DebugPreset =
  | 'teen'
  | 'youngAdult'
  | 'adult'
  | 'wealthy'
  | 'lowEnergy'
  | 'relationships';

type DebugGrantMode = 'add' | 'set';

const MAX_GRANT_ENERGY = 100;
const MAX_GRANT_DIAMONDS = 10_000;
const MAX_GRANT_MONEY = 1_000_000;

export function isDebugEnabled(): boolean {
  return config.DEBUG || process.env.NODE_ENV !== 'production';
}

function sendDebugDisabled(session: PlayerSession): void {
  session.send({
    type: 'error',
    message: 'Debug commands are disabled. Set DEBUG=true on the server.',
  });
}

function applyDebugPreset(session: PlayerSession, preset: DebugPreset): void {
  const character = session.player.c;

  switch (preset) {
    case 'teen':
      character.ageYears = 15;
      character.money = 100;
      character.energy = 80;
      break;
    case 'youngAdult':
      character.ageYears = 22;
      character.money = 500;
      character.energy = 90;
      break;
    case 'adult':
      character.ageYears = 35;
      character.money = 2000;
      character.energy = 85;
      break;
    case 'wealthy':
      character.money = 100_000;
      character.diamonds = 500;
      character.energy = 100;
      break;
    case 'lowEnergy':
      character.energy = 5;
      character.calcEnergy = 5;
      break;
    case 'relationships':
      character.happiness = 80;
      break;
  }
}

export async function handleDebugSetup(payload: unknown, session: PlayerSession): Promise<void> {
  if (!isDebugEnabled()) {
    sendDebugDisabled(session);
    return;
  }

  const preset = resolvePayloadId(payload, 'preset') as DebugPreset | undefined;
  if (!preset) {
    session.send({
      type: 'error',
      message: 'Missing debug preset.',
    });
    return;
  }

  applyDebugPreset(session, preset);
  getPeakEnergy(session.player.c);
  await session.savePlayer();
  session.sendPlayerObject();
  session.send({
    type: 'debugSetupComplete',
    success: true,
    preset,
    message: `Applied debug preset "${preset}".`,
  });
}

interface DebugGrantApplied {
  money?: number;
  energy?: number;
  diamonds?: number;
}

function clampGrantAmount(
  value: number | undefined,
  max: number
): number | undefined {
  if (value === undefined) {
    return undefined;
  }
  if (!Number.isFinite(value) || value < 0 || value > max) {
    return undefined;
  }
  return value;
}

function applyDebugGrant(
  session: PlayerSession,
  grants: { money?: number; energy?: number; diamonds?: number },
  mode: DebugGrantMode
): DebugGrantApplied {
  const character = session.player.c;
  const applied: DebugGrantApplied = {};
  let energyChanged = false;

  if (grants.energy !== undefined) {
    if (mode === 'set') {
      character.energy = setStat(grants.energy, 'energy');
    } else {
      character.energy = modifyStat(character.energy, grants.energy, 'energy');
    }
    applied.energy = character.energy;
    energyChanged = true;
  }

  if (grants.money !== undefined) {
    if (mode === 'set') {
      character.money = Math.max(0, grants.money);
    } else {
      character.money = Math.max(0, (character.money ?? 0) + grants.money);
    }
    applied.money = character.money;
  }

  if (grants.diamonds !== undefined) {
    if (mode === 'set') {
      character.diamonds = Math.max(0, Math.round(grants.diamonds));
    } else {
      character.diamonds = Math.max(0, Math.round((character.diamonds ?? 0) + grants.diamonds));
    }
    applied.diamonds = character.diamonds;
  }

  if (energyChanged) {
    getPeakEnergy(character);
  }

  return applied;
}

export async function handleDebugGrant(payload: unknown, session: PlayerSession): Promise<void> {
  if (!isDebugEnabled()) {
    sendDebugDisabled(session);
    return;
  }

  const rawMoney = resolvePayloadNumber(payload, 'money');
  const rawEnergy = resolvePayloadNumber(payload, 'energy');
  const rawDiamonds = resolvePayloadNumber(payload, 'diamonds');
  const modeField = resolvePayloadField(payload, 'mode');
  const mode: DebugGrantMode = modeField === 'set' ? 'set' : 'add';

  const money = clampGrantAmount(rawMoney, MAX_GRANT_MONEY);
  const energy = clampGrantAmount(rawEnergy, MAX_GRANT_ENERGY);
  const diamonds = clampGrantAmount(rawDiamonds, MAX_GRANT_DIAMONDS);

  if (
    (rawMoney !== undefined && money === undefined) ||
    (rawEnergy !== undefined && energy === undefined) ||
    (rawDiamonds !== undefined && diamonds === undefined)
  ) {
    session.send({
      type: 'error',
      message: 'Invalid debug grant amounts. Check per-request limits.',
    });
    return;
  }

  if (money === undefined && energy === undefined && diamonds === undefined) {
    session.send({
      type: 'error',
      message: 'Missing debug grant fields. Provide money, energy, and/or diamonds.',
    });
    return;
  }

  const applied = applyDebugGrant(session, { money, energy, diamonds }, mode);
  await session.savePlayer();
  session.sendPlayerObject();
  session.send({
    type: 'debugGrantComplete',
    success: true,
    applied,
    mode,
    message: 'Debug resources applied.',
  });
}
