/**
 * Energy System - Manages player energy for various game actions
 *
 * Features:
 * - Energy regeneration over time (1 energy per 5 frames by default)
 * - Energy consumption for actions (building placement, rewind usage)
 * - Configurable max energy and regeneration rate
 * - Event system for energy changes
 * - Rewind mode detection to pause regeneration
 */

export interface EnergyConfig {
  maxEnergy: number;
  regenerationRate: number; // frames between energy regeneration
  initialEnergy?: number;
}

export interface EnergyChangeEvent {
  currentEnergy: number;
  maxEnergy: number;
  previousEnergy: number;
  changeAmount: number;
  reason: string;
}

export default class EnergySystem {
  private currentEnergy: number;
  private maxEnergy: number;
  private regenerationRate: number; // frames between regeneration
  private framesSinceLastRegen: number = 0;
  private isRewindMode: boolean = false;
  private scene: Phaser.Scene;
  private isTutorialRegenerationDisabled: boolean = false;

  // Event callbacks
  private onEnergyChangeCallbacks: ((event: EnergyChangeEvent) => void)[] = [];

  constructor(scene: Phaser.Scene, config: EnergyConfig) {
    this.scene = scene;
    this.maxEnergy = config.maxEnergy;
    this.regenerationRate = config.regenerationRate;
    this.currentEnergy = config.initialEnergy ?? config.maxEnergy;

    console.log(
      `EnergySystem initialized: ${this.currentEnergy}/${this.maxEnergy} energy, regen every ${this.regenerationRate} frames`
    );
  }

  /**
   * Update the energy system - should be called every frame
   */
  public update(): void {
    // Only regenerate energy if not in rewind mode, not at max energy, and tutorial regeneration is not disabled
    if (
      !this.isRewindMode &&
      !this.isTutorialRegenerationDisabled &&
      this.currentEnergy < this.maxEnergy
    ) {
      this.framesSinceLastRegen++;

      if (this.framesSinceLastRegen >= this.regenerationRate) {
        this.addEnergy(1, "regeneration");
        this.framesSinceLastRegen = 0;
      }
    }
  }

  /**
   * Add energy to the current amount
   */
  public addEnergy(amount: number, reason: string = "unknown"): boolean {
    if (amount <= 0) return false;

    const previousEnergy = this.currentEnergy;
    const newEnergy = Math.min(this.maxEnergy, this.currentEnergy + amount);
    const actualChange = newEnergy - this.currentEnergy;

    if (actualChange > 0) {
      this.currentEnergy = newEnergy;
      this.notifyEnergyChange(previousEnergy, actualChange, reason);
      return true;
    }

    return false;
  }

  /**
   * Consume energy if available
   */
  public consumeEnergy(amount: number, reason: string = "unknown"): boolean {
    if (amount <= 0) return true; // No energy needed
    if (this.currentEnergy < amount) return false; // Not enough energy

    const previousEnergy = this.currentEnergy;
    this.currentEnergy -= amount;
    this.notifyEnergyChange(previousEnergy, -amount, reason);
    return true;
  }

  /**
   * Check if enough energy is available
   */
  public hasEnergy(amount: number): boolean {
    return this.currentEnergy >= amount;
  }

  /**
   * Get current energy amount
   */
  public getCurrentEnergy(): number {
    return this.currentEnergy;
  }

  /**
   * Get maximum energy amount
   */
  public getMaxEnergy(): number {
    return this.maxEnergy;
  }

  /**
   * Get energy as a percentage (0-1)
   */
  public getEnergyPercentage(): number {
    return this.maxEnergy > 0 ? this.currentEnergy / this.maxEnergy : 0;
  }

  /**
   * Set rewind mode state - affects energy regeneration
   */
  public setRewindMode(isRewindMode: boolean): void {
    this.isRewindMode = isRewindMode;

    // Reset regeneration timer when exiting rewind mode
    if (!isRewindMode) {
      this.framesSinceLastRegen = 0;
    }
  }

  /**
   * Check if currently in rewind mode
   */
  public isInRewindMode(): boolean {
    return this.isRewindMode;
  }

  /**
   * Set tutorial regeneration disabled state - prevents energy regeneration during tutorial
   */
  public setTutorialRegenerationDisabled(disabled: boolean): void {
    this.isTutorialRegenerationDisabled = disabled;

    // Reset regeneration timer when enabling regeneration
    if (!disabled) {
      this.framesSinceLastRegen = 0;
    }

    console.log(
      `Energy regeneration ${disabled ? "disabled" : "enabled"} for tutorial`
    );
  }

  /**
   * Check if tutorial regeneration is disabled
   */
  public isTutorialRegenerationDisabledState(): boolean {
    return this.isTutorialRegenerationDisabled;
  }

  /**
   * Set maximum energy (useful for upgrades)
   */
  public setMaxEnergy(maxEnergy: number): void {
    if (maxEnergy <= 0) return;

    const previousEnergy = this.currentEnergy;
    this.maxEnergy = maxEnergy;

    // If current energy exceeds new max, cap it
    if (this.currentEnergy > this.maxEnergy) {
      this.currentEnergy = this.maxEnergy;
      this.notifyEnergyChange(
        previousEnergy,
        this.currentEnergy - previousEnergy,
        "max_energy_changed"
      );
    }
  }

  /**
   * Set regeneration rate (frames between regeneration)
   */
  public setRegenerationRate(rate: number): void {
    if (rate <= 0) return;
    this.regenerationRate = rate;
  }

  /**
   * Subscribe to energy change events
   */
  public onEnergyChange(callback: (event: EnergyChangeEvent) => void): void {
    this.onEnergyChangeCallbacks.push(callback);
  }

  /**
   * Unsubscribe from energy change events
   */
  public offEnergyChange(callback: (event: EnergyChangeEvent) => void): void {
    const index = this.onEnergyChangeCallbacks.indexOf(callback);
    if (index !== -1) {
      this.onEnergyChangeCallbacks.splice(index, 1);
    }
  }

  /**
   * Notify all subscribers of energy changes
   */
  private notifyEnergyChange(
    previousEnergy: number,
    changeAmount: number,
    reason: string
  ): void {
    const event: EnergyChangeEvent = {
      currentEnergy: this.currentEnergy,
      maxEnergy: this.maxEnergy,
      previousEnergy,
      changeAmount,
      reason,
    };

    this.onEnergyChangeCallbacks.forEach((callback) => {
      try {
        callback(event);
      } catch (error) {
        console.error("Error in energy change callback:", error);
      }
    });
  }

  /**
   * Reset energy to full
   */
  public resetEnergy(): void {
    const previousEnergy = this.currentEnergy;
    this.currentEnergy = this.maxEnergy;
    this.framesSinceLastRegen = 0;
    this.notifyEnergyChange(
      previousEnergy,
      this.maxEnergy - previousEnergy,
      "reset"
    );
  }

  /**
   * Get debug information about the energy system
   */
  public getDebugInfo(): string {
    return `Energy: ${this.currentEnergy}/${this.maxEnergy} (${(
      this.getEnergyPercentage() * 100
    ).toFixed(1)}%) | Rewind: ${this.isRewindMode} | Frames to regen: ${
      this.regenerationRate - this.framesSinceLastRegen
    }`;
  }

  /**
   * Destroy the energy system and clean up
   */
  public destroy(): void {
    this.onEnergyChangeCallbacks = [];
  }
}
