//load local dependencies
const EventEmitter = require('events');
const StateManager = require('./stateManager');
const MovementManager = require('./movementManager');

//load all config modules
const defaultConfig = require('./stateConfig.json');
const ConfigUtils = require('../helper/configUtils');

class state{
  constructor(config = {}, logger) {

    this.emitter = new EventEmitter();  // Own EventEmitter
    this.configUtils = new ConfigUtils(defaultConfig);
    this.config = this.configUtils.initConfig(config);
    this.abortController = null;  // new abort controller for aborting async tasks
    // Init after config is set
    this.logger = logger;

    // Initialize StateManager for state handling
    this.stateManager = new StateManager(this.config,this.logger);
    this.movementManager = new MovementManager(this.config, this.logger, this.emitter);

    this.delayedMove = null;
    this.mode = this.config.mode.current;

    // Log initialization
    this.logger.info("State class initialized.");

  }

  // -------- Delegate State Management -------- //

  getMoveTimeLeft() {
    return this.movementManager.timeleft;
  }
  
  getCurrentState() {
    return this.stateManager.currentState;
  }

  getStateDescription() {
    return this.stateManager.getStateDescription();
  }

  // -------- Movement Methods -------- //
  getCurrentPosition() {
    return this.movementManager.getCurrentPosition();
  }

  getRunTimeHours() {
    return this.stateManager.getRunTimeHours();
  }

  getMaintenanceTimeHours(){
    return this.stateManager.getMaintenanceTimeHours();
  }

 
  async moveTo(targetPosition) {

    // Check for invalid conditions and throw errors
    if (targetPosition === this.getCurrentPosition()) {
      this.logger.warn(`Target position=${targetPosition} is the same as the current position ${this.getCurrentPosition()}. Not executing move.`);
      return;
    }

    if (this.stateManager.getCurrentState() !== "operational") {
      if (this.config.mode.current === "auto") {
        this.delayedMove = targetPosition;
        this.logger.warn(`Saving setpoint=${targetPosition} to execute once back in 'operational' state.`);
      }
      else{
        this.logger.warn(`Not able to accept setpoint=${targetPosition} while not in ${this.stateManager.getCurrentState()} state`);
      }
      //return early
      return;
    }
    this.abortController = new AbortController();
    const { signal } = this.abortController;
    try {
      const newState = targetPosition < this.getCurrentPosition() ? "decelerating" : "accelerating";
      await this.transitionToState(newState,signal);  // awaits transition
      await this.movementManager.moveTo(targetPosition,signal);  // awaits moving
      this.emitter.emit("movementComplete", { position: targetPosition });
      await this.transitionToState("operational");
    } catch (error) {
      this.logger.error(error);
    }
  }
  
  // -------- State Transition Methods -------- //

  abortCurrentMovement(reason = "group override") {
    if (this.abortController && !this.abortController.signal.aborted) {
      this.logger.warn(`Aborting movement: ${reason}`);
      this.abortController.abort();
    }
  }

  async transitionToState(targetState, signal) {

    const fromState = this.getCurrentState();
    const position = this.getCurrentPosition();

    // Define states that cannot be aborted for safety reasons
    const protectedStates = ['warmingup', 'coolingdown'];
    const isProtectedTransition = protectedStates.includes(fromState);

    try {
      
      this.logger.debug(`Starting transition from ${fromState} to ${targetState}.`);
      if( isProtectedTransition){
        //overrule signal to prevent abortion
        signal = null; // Disable abortion for protected states
        //spit warning
        this.logger.warn(`Transition from ${fromState} to ${targetState} is protected and cannot be aborted.`);
      }

      // Await the state transition and pass signal for abortion
      const feedback = await this.stateManager.transitionTo(targetState,signal);
      this.logger.info(`Statemanager: ${feedback}`);
      
      /* -- Auto pick setpoints in auto mode when operational--*/
      if (
          targetState === "operational" &&
          this.config.mode.current === "auto" &&
          this.delayedMove !== position &&
          this.delayedMove
      ) {
          this.logger.info(`Automatically picking up on last requested setpoint ${this.delayedMove}`);
          //trigger move 
          await this.moveTo(this.delayedMove,signal);
          this.delayedMove = null;
          this.logger.info(`moveTo : ${feedback} `);
      }

      this.logger.info(`State change to ${targetState} completed.`);
      this.emitter.emit('stateChange', targetState); // <-- Implement Here
    } catch (error) {
        if (
        error.message === "Transition aborted" ||
        error.message === "Movement aborted"
      ) {
        throw error;
      }
        this.logger.error(error);
    }
  }

}

module.exports = state;

