/**
 * otpStateMachine.js
 * OTP Testing & Automation Framework — State Machine
 *
 * FOR DEV / STAGING / QA / ACCESSIBILITY TESTING ONLY.
 *
 * States:
 *   IDLE → OTP_DETECTED → WAITING_OTP → OTP_RECEIVED →
 *   OTP_FILLED → OTP_VERIFIED | OTP_FAILED → COOLDOWN → STOPPED
 */
(function initVisaFlowXOtpStateMachine(global) {
  "use strict";

  const STATES = Object.freeze({
    IDLE:         "IDLE",
    OTP_DETECTED: "OTP_DETECTED",
    WAITING_OTP:  "WAITING_OTP",
    OTP_RECEIVED: "OTP_RECEIVED",
    OTP_FILLED:   "OTP_FILLED",
    OTP_VERIFIED: "OTP_VERIFIED",
    OTP_FAILED:   "OTP_FAILED",
    COOLDOWN:     "COOLDOWN",
    STOPPED:      "STOPPED"
  });

  // Valid transitions map
  const TRANSITIONS = {
    IDLE:         ["OTP_DETECTED"],
    OTP_DETECTED: ["WAITING_OTP", "STOPPED"],
    WAITING_OTP:  ["OTP_RECEIVED", "OTP_FAILED", "COOLDOWN", "STOPPED"],
    OTP_RECEIVED: ["OTP_FILLED",   "OTP_FAILED"],
    OTP_FILLED:   ["OTP_VERIFIED", "OTP_FAILED"],
    OTP_VERIFIED: ["IDLE",         "STOPPED"],
    OTP_FAILED:   ["COOLDOWN",     "WAITING_OTP", "STOPPED"],
    COOLDOWN:     ["WAITING_OTP",  "STOPPED"],
    STOPPED:      ["IDLE"]
  };

  function log(msg) {
    console.log("[VisaFlowX][OtpStateMachine]", msg);
  }

  class OtpStateMachine {
    constructor() {
      this._state     = STATES.IDLE;
      this._listeners = [];
      this._history   = [];
    }

    get state() { return this._state; }

    /** Transition to a new state (validated). Returns true if successful. */
    transition(nextState, meta = {}) {
      const allowed = TRANSITIONS[this._state] || [];
      if (!allowed.includes(nextState)) {
        log(`Invalid transition: ${this._state} → ${nextState}`);
        return false;
      }
      const prev    = this._state;
      this._state   = nextState;
      const entry   = { from: prev, to: nextState, at: new Date().toISOString(), ...meta };
      this._history.push(entry);
      log(`State: ${prev} → ${nextState}`);
      this._listeners.forEach((fn) => { try { fn(entry); } catch (_) {} });
      return true;
    }

    /** Register a listener called on every valid transition. */
    onTransition(fn) {
      if (typeof fn === "function") this._listeners.push(fn);
    }

    reset() {
      this._state   = STATES.IDLE;
      this._history = [];
      log("State machine reset");
    }

    /** Return a read-only copy of transition history. */
    history() {
      return [...this._history];
    }

    is(state) { return this._state === state; }
    isIdle()       { return this._state === STATES.IDLE; }
    isOtpDetected(){ return this._state === STATES.OTP_DETECTED; }
    isWaiting()    { return this._state === STATES.WAITING_OTP; }
    isReceived()   { return this._state === STATES.OTP_RECEIVED; }
    isFilled()     { return this._state === STATES.OTP_FILLED; }
    isVerified()   { return this._state === STATES.OTP_VERIFIED; }
    isFailed()     { return this._state === STATES.OTP_FAILED; }
    isCooldown()   { return this._state === STATES.COOLDOWN; }
    isStopped()    { return this._state === STATES.STOPPED; }
  }

  const OtpStateMachineModule = Object.freeze({ STATES, OtpStateMachine });

  global.VisaFlowX = Object.assign(global.VisaFlowX || {}, { OtpStateMachine: OtpStateMachineModule });

  if (typeof module !== "undefined" && module.exports) {
    module.exports = OtpStateMachineModule;
  }
})(typeof globalThis !== "undefined" ? globalThis : this);
