/**
 * Energy Refill System
 *
 * Handles energy refill purchases using diamonds.
 * Supports multiple tiers including unlimited energy for 24 hours.
 */

import { deductDiamonds, canAfford } from './diamondEconomy.js';
import type { Player } from '../models/Player.js';

export interface RefillTier {
  energy: number;
  diamonds: number;
}

export interface RefillResult {
  success: boolean;
  message: string;
  newBalance?: {
    energy: number;
    diamonds: number;
    unlimitedUntil: string | null;
  };
}

// Refill tier configurations
export const REFILL_TIERS: Record<string, RefillTier> = {
  small: { energy: 20, diamonds: 10 },
  medium: { energy: 50, diamonds: 20 },
  full: { energy: 100, diamonds: 35 },
  unlimited_24h: { energy: 0, diamonds: 50 }, // Special case
};

// In-memory unlimited energy tracking
const unlimitedEnergyUntil: Map<string, Date> = new Map();

// Rate limiting (simple in-memory)
const purchaseTimestamps: Map<string, number[]> = new Map();
const RATE_LIMIT_CALLS = 10;
const RATE_LIMIT_WINDOW_MS = 60000;

/**
 * Check rate limit for a player
 */
function checkRateLimit(playerId: string): boolean {
  const now = Date.now();
  const timestamps = purchaseTimestamps.get(playerId) ?? [];

  // Remove old timestamps
  const recentTimestamps = timestamps.filter(t => now - t < RATE_LIMIT_WINDOW_MS);

  if (recentTimestamps.length >= RATE_LIMIT_CALLS) {
    return false; // Rate limited
  }

  recentTimestamps.push(now);
  purchaseTimestamps.set(playerId, recentTimestamps);

  return true;
}

/**
 * Handle energy refill purchase.
 *
 * Reads the player's REAL energy/diamonds from the authoritative server-side
 * `player` (never the client), deducts diamonds, and writes the refilled energy
 * back onto `player.c` so the refill actually sticks (previously it only echoed
 * a number to the client that the next state push overwrote, and deductDiamonds
 * silently failed because it got a bare playerId with no player context).
 */
export function purchaseEnergyRefill(
  player: Player,
  refillType: string,
  maxEnergy = 100
): RefillResult {
  const playerId = player.userId;
  // Check rate limit
  if (!checkRateLimit(playerId)) {
    return {
      success: false,
      message: 'Rate limited. Please wait before making another purchase.',
    };
  }

  // Validate refill type
  if (!(refillType in REFILL_TIERS)) {
    return {
      success: false,
      message: `Invalid refill type: ${refillType}`,
    };
  }

  const tier = REFILL_TIERS[refillType];
  const diamondCost = tier.diamonds;

  // Check if player can afford (reads player.c.diamonds)
  if (!canAfford(player as never, diamondCost)) {
    return {
      success: false,
      message: `Not enough diamonds. Need ${diamondCost}.`,
    };
  }

  // Read the player's REAL current base energy.
  const currentEnergy = player.c.energy ?? 0;

  // Calculate new values
  let newEnergy: number;
  let unlimitedUntil: Date | null = null;

  if (refillType === 'unlimited_24h') {
    // Special case: unlimited energy for 24 hours
    unlimitedUntil = new Date(Date.now() + 24 * 60 * 60 * 1000);
    newEnergy = maxEnergy;
    unlimitedEnergyUntil.set(playerId, unlimitedUntil);
  } else {
    // Normal refill: add energy up to max
    newEnergy = Math.min(currentEnergy + tier.energy, maxEnergy);
  }

  // Deduct diamonds from the real player (player.c.diamonds).
  const deductResult = deductDiamonds(player as never, `energy_refill_${refillType}`, diamondCost);

  if (!deductResult.success) {
    return {
      success: false,
      message: deductResult.message,
    };
  }

  // APPLY the refill to authoritative server state so it persists. calcEnergy is
  // the effective spendable energy (base minus the habit/activity peakEnergy
  // penalty), mirroring the per-hour recompute in the game loop.
  player.c.energy = newEnergy;
  player.c.calcEnergy = Math.max(0, newEnergy - (player.c.peakEnergy ?? 0));

  console.log(`Player ${playerId} purchased ${refillType} refill for ${diamondCost} diamonds`);

  return {
    success: true,
    message: 'Energy refilled successfully',
    newBalance: {
      energy: newEnergy,
      diamonds: deductResult.newBalance ?? 0,
      unlimitedUntil: unlimitedUntil?.toISOString() ?? null,
    },
  };
}

/**
 * Check if player currently has unlimited energy active
 */
export function checkUnlimitedEnergy(playerId: string): boolean {
  const until = unlimitedEnergyUntil.get(playerId);

  if (!until) {
    return false;
  }

  if (new Date() < until) {
    return true;
  }

  // Expired, clear it
  unlimitedEnergyUntil.delete(playerId);
  return false;
}

/**
 * Get time remaining on unlimited energy
 */
export function getUnlimitedEnergyTimeRemaining(playerId: string): number | null {
  const until = unlimitedEnergyUntil.get(playerId);

  if (!until) {
    return null;
  }

  const remaining = until.getTime() - Date.now();

  if (remaining <= 0) {
    unlimitedEnergyUntil.delete(playerId);
    return null;
  }

  return Math.floor(remaining / 1000); // Return seconds
}

/**
 * WebSocket message handler for purchaseEnergyRefill
 */
export function handlePurchaseEnergyRefill(
  player: Player,
  messageData: { refillType?: string; maxEnergy?: number },
  sendToClient: (playerId: string, message: Record<string, unknown>) => void
): void {
  const playerId = player.userId;
  const { refillType, maxEnergy = 100 } = messageData;

  if (!refillType) {
    sendToClient(playerId, {
      type: 'error',
      errorCode: 'INVALID_REQUEST',
      message: 'Missing refillType',
    });
    return;
  }

  const result = purchaseEnergyRefill(player, refillType, maxEnergy);

  if (result.success) {
    sendToClient(playerId, {
      type: 'purchaseComplete',
      category: 'energy',
      success: true,
      newBalance: result.newBalance,
    });

    // Python format: data spread at root level, not nested in 'data'
    sendToClient(playerId, {
      type: 'playerUpdate',
      energy: result.newBalance?.energy,
      diamonds: result.newBalance?.diamonds,
      unlimitedEnergyUntil: result.newBalance?.unlimitedUntil,
    });
  } else {
    sendToClient(playerId, {
      type: 'error',
      errorCode: 'PURCHASE_FAILED',
      message: result.message,
    });
  }
}

/**
 * Get all available refill tiers
 */
export function getRefillTiers(): Record<string, RefillTier> {
  return { ...REFILL_TIERS };
}

/**
 * Clear unlimited energy for player (for testing)
 */
export function clearUnlimitedEnergy(playerId: string): void {
  unlimitedEnergyUntil.delete(playerId);
}

/**
 * Clear all energy data (for testing)
 */
export function clearAllEnergyData(): void {
  unlimitedEnergyUntil.clear();
  purchaseTimestamps.clear();
}
