import {SETTINGS} from "../../constants/constants";
import EmbeddedSpineButton from "./EmbeddedSpineButton.js";
import {Skin} from "@pixi-spine/runtime-4.1";
import EmbeddedSpineCheckbox from "./EmbeddedSpineCheckbox.js";
import EmbeddedTextField from "./EmbeddedTextField.js";
import SpineScene from "../SpineScene";
import TextAttachment from "../TextAttachment.js";
import {createStyles} from "../../utils/styles";
import Locator from "../../services/Locator";
import {State} from "@popiplay/state-machine";

const style = createStyles({
  skinFolder: "desktop",
  "(max-height: 550px) and (orientation: landscape)": {
    skinFolder: "mobile",
  },
  "(orientation: portrait)": {
    skinFolder: "mobile",
  }
});

const SETTINGS_MODES = {
  BASIC: 0,
  ADVANCED: 1,
};

const DISPLAYING_STATES = {
  HIDDEN: 0,
  SHOWN: 1
};

export default class AutoSpinsSettings extends SpineScene {
  constructor(inputs, options) {
    super("autospins_settings");
    this.inputs = inputs;
    this.options = options;
    // this.visible = false;
    this.stateData.setMix("states/collapsed", "states/expanded", 0.1);
    this.stateData.setMix("states/expanded", "states/collapsed", 0.1);
    this.slotContainers[this.skeleton.findSlotIndex("desktop_bg")].eventMode = "static";
    this.slotContainers[this.skeleton.findSlotIndex("mobile_bg")].eventMode = "static";
    this.createTexts();
    this.setupButtons();
    this.createStates();
    this.setupListeners();
  }

  createStates() {
    this.settingsModes = [
      new BasicSettingsState(this),
      new AdvancedSettingsState(this),
    ];
    this.setSettingsMode(SETTINGS_MODES.BASIC);

    this.displayingStates = [
      new HiddenState(this),
      new ShownState(this)
    ];
    this.setDisplayingState(DISPLAYING_STATES.SHOWN);
  }

  setupButtons() {
    let track = 3;

    const asBtn = new EmbeddedSpineButton(this, "as_btn", ++track, ++track);
    const closeBtn = new EmbeddedSpineButton(this, "close_btn", ++track, ++track);

    const amountButtonsBone = this.skeleton.findBone("amount_buttons");
    const amountButtons = amountButtonsBone.children.map((bone, i) => {
      return new EmbeddedSpineButton(this, bone.data.name, ++track, ++track);
    });

    this.anyWinCheckbox = new EmbeddedSpineCheckbox(this, "checkbox_any_win", ++track, ++track, ++track);
    this.bonusWonCheckbox = new EmbeddedSpineCheckbox(this, "checkbox_bonus_won", ++track, ++track, ++track);
    this.winExceedsCheckbox = new EmbeddedSpineCheckbox(this, "checkbox_win_exceeds", ++track, ++track, ++track);
    this.balanceIncreaseCheckbox = new EmbeddedSpineCheckbox(this, "checkbox_balance_increases", ++track, ++track, ++track);
    this.balanceDecreaseCheckbox = new EmbeddedSpineCheckbox(this, "checkbox_balance_decreases", ++track, ++track, ++track);

    this.winExceedsTextField = new EmbeddedTextField(this, "textfield_win_exceeds", ++track, this.options);
    this.winExceedsTextField.on("change", (e) => {
      const parsedValue = this.parseTextFieldValue(e.value);
      this.winExceedsTextField.input.value = parsedValue;
      this.winExceedsTextField.textObject.text = parsedValue;
      this.winExceedsCheckbox.checked = !!parsedValue;
      this.inputs.winExceedsTextField = parsedValue;
    });
    this.winExceedsTextField.enable();
    this.balanceIncreaseTextField = new EmbeddedTextField(this, "textfield_balance_increases", ++track, this.options);
    this.balanceIncreaseTextField.on("change", (e) => {
      const parsedValue = this.parseTextFieldValue(e.value);
      this.balanceIncreaseTextField.input.value = parsedValue;
      this.balanceIncreaseTextField.textObject.text = parsedValue;
      this.balanceIncreaseCheckbox.checked = !!parsedValue;
      this.inputs.balanceIncreaseTextField = parsedValue;
    });
    this.balanceIncreaseTextField.enable();
    this.balanceDecreaseTextField = new EmbeddedTextField(this, "textfield_balance_decreases", ++track, this.options);
    this.balanceDecreaseTextField.on("change", (e) => {
      const parsedValue = this.parseTextFieldValue(e.value);
      this.balanceDecreaseTextField.input.value = parsedValue;
      this.balanceDecreaseTextField.textObject.text = parsedValue;
      this.balanceDecreaseCheckbox.checked = !!parsedValue;
      this.inputs.balanceDecreaseTextField = parsedValue;
    });
    this.balanceDecreaseTextField.enable();
    this.skin = new Skin("mixed");
  }

  setupListeners() {
    this.state.addListener({
      event: (entity, event) => {
        if (event.data.name === "as_btn/up") this.inputs.isAutoGameSettingsModeButtonPressed = false;
        if (event.data.name === "as_btn/upoutside") this.inputs.isAutoGameSettingsModeButtonPressed = false;
        if (event.data.name === "as_btn/down") this.inputs.isAutoGameSettingsModeButtonPressed = true;
        if (event.data.name === "close_btn/up") this.handleCloseBtnUp();
        if (event.data.name === "checked" && event.stringValue === "anyWin") {
          this.winExceedsCheckbox.checked = false;
          this.balanceIncreaseCheckbox.checked = false;
        }
        if (event.data.name === "checked" && event.stringValue === "singleWinExceeds") {
          this.anyWinCheckbox.checked = false;
          this.winExceedsTextField.focus();
        }
        if (event.data.name === "checked" && event.stringValue === "balanceIncreasesBy") {
          this.anyWinCheckbox.checked = false;
          this.balanceIncreaseTextField.focus();
        }
        if (event.data.name === "checked" && event.stringValue === "balanceDecreasesBy") {
          this.balanceDecreaseTextField.focus();
        }
        if (event.data.name === "unchecked" && event.stringValue === "singleWinExceeds") {
          this.winExceedsTextField.clear();
        }
        if (event.data.name === "unchecked" && event.stringValue === "balanceIncreasesBy") {
          this.balanceIncreaseTextField.clear();
        }
        if (event.data.name === "unchecked" && event.stringValue === "balanceDecreasesBy") {
          this.balanceDecreaseTextField.clear();
        }
        this.inputs.isAnyWinChecked = this.anyWinCheckbox.checked;
        this.inputs.isBonusWonChecked = this.bonusWonCheckbox.checked;
        this.inputs.isSingleWinExceedsChecked = this.winExceedsCheckbox.checked;
        this.inputs.isBalanceIncreaseChecked = this.balanceIncreaseCheckbox.checked;
        this.inputs.isBalanceDecreaseChecked = this.balanceDecreaseCheckbox.checked;

        if (event.data.name === "pick") {
          this.inputs.autoRoundsIssued = event.intValue || Infinity;
        }
        this.emit(event.data.name, event);
      }
    });
  }

  globalUpHandler() {
    this.inputs.isAutoGameButtonPressed = false;
  }

  globalDownHandler(e) {
    if (!this.isClickOnWindow(e)) {
      this.inputs.isAutoGameButtonPressed = true;
    }
  }

  handleCloseBtnUp() {
    this.inputs.isAutoGameSettingsShown = false;
  }

  isClickOnWindow(e) {
    const objects = Locator.renderer.events.rootBoundary.hitTestRecursive(
      this,
      "passive",
      e.global,
      Locator.renderer.events.rootBoundary.hitTestFn,
      Locator.renderer.events.rootBoundary.hitPruneFn
    );
    return objects && objects.length > 0;
  }

  show() {
    this.visible = true;
    this.state.setAnimation(0, "states/shown", false);
    Locator.events.on("globalpointerdown", this.globalDownHandler, this);
    Locator.events.on("globalpointerup", this.globalUpHandler, this);
  }

  hide() {
    this.state.setAnimation(0, "states/hidden", false);
    Locator.events.off("globalpointerdown", this.globalDownHandler, this);
    Locator.events.off("globalpointerup", this.globalUpHandler, this);
    this.visible = false;
  }

  update(dt = 0) {
    this.currentSettingsMode.handleInput(this.inputs.isAdvancedAutoGameSettings);
    this.currentDisplayingState.handleInput(this.inputs.isAutoGameSettingsShown);
    super.update(dt);
  }

  resize() {
    this.position.set(SETTINGS.viewport.width * 0.5, SETTINGS.viewport.height);

    this.skin.clear();
    this.skin.addSkin(this.spineData.findSkin(this.buildPositionSkinName()));
    this.skin.addSkin(this.spineData.findSkin(this.buildWindowSkinName()));
    this.skin.addSkin(this.spineData.findSkin(this.buildAmountGroupSkinName()));
    this.skeleton.setSkin(null);
    this.skeleton.setToSetupPose();
    this.skeleton.setSkin(this.skin);

    const x = Math.min(SETTINGS.viewport.width * 0.5 - Locator.viewport.left, 450);
    this.skeleton.findBone("right").x = x;
    this.skeleton.findBone("left").x = -x;
    this.skeleton.findBone("top").y = SETTINGS.viewport.height;

    const mobileScaleBone = this.skeleton.findBone("mobile_scale");
    const mobileScale = Math.min(Locator.viewport.cropWidthRatio * SETTINGS.viewport.width / 350, 0.9);
    mobileScaleBone.scaleX = mobileScaleBone.scaleY = mobileScale;

    // advanced settings halding on resize
    if (this.buildPositionSkinName().startsWith('mobile')) {
      if (!this.originalSettings) {
        this.originalSettings = {
          isAdvancedAutoGameSettings: this.inputs.isAdvancedAutoGameSettings,
          mode: this.settingsModes.indexOf(this.currentSettingsMode),
        };
        this.inputs.isAdvancedAutoGameSettings = true;
        this.setSettingsMode(SETTINGS_MODES.ADVANCED);
      }
    } else if (this.originalSettings) {
      this.inputs.isAdvancedAutoGameSettings = this.originalSettings.isAdvancedAutoGameSettings;
      this.setSettingsMode(this.originalSettings.mode);
      delete this.originalSettings;
    }
  }

  buildPositionSkinName() {
    const factor = this.getWidthPercent();
    return style.skinFolder + "/" + ">" + factor;
  }

  buildWindowSkinName() {
    return style.skinFolder + "/window";
  }

  buildAmountGroupSkinName() {
    return style.skinFolder + "/amount_group";
  }

  getWidthPercent() {
    return Math.floor(Locator.viewport.cropWidthRatio * 10) * 10;
  }

  destroy(...args) {
    this.winExceedsTextField.destroy();
    this.balanceDecreaseTextField.destroy();
    this.balanceIncreaseTextField.destroy();
    Locator.events.off("globalpointerdown", this.globalDownHandler, this);
    Locator.events.off("globalpointerup", this.globalUpHandler, this);
    super.destroy(...args);
  }

  setBasicMode() {
    this.state.setAnimation(1, "states/collapsed", false);
  }

  setAdvancedMode() {
    this.state.setAnimation(1, "states/expanded", false);
  }

  setSettingsMode(mode) {
    this.currentSettingsMode = this.settingsModes[mode];
    this.currentSettingsMode.enter();
  }

  setDisplayingState(state) {
    this.currentDisplayingState = this.displayingStates[state];
    this.currentDisplayingState.enter();
  }

  createTexts() {
    this.titleText = new TextAttachment({width: 170, height: 24}, this.options);
    this.titleText.content = {key: 'ui_autospins_title'};
    this.titleText.style = {
      fill: 0xffffff,
      fontFamily: "Oxanium, Opensans",
      fontSize: 22,
      fontWeight: "bold",
    };
    this.titleText.autoScaleToFit = true;
    this.titleText.boundaries = false;
    this.titleText.attachTo(this, "txt_Autospin settings");

    this.advancedBtnText = new TextAttachment({width: 70, height: 20}, this.options);
    this.advancedBtnText.content = {key: "ui_autospins_advanced"};
    this.advancedBtnText.style = {
      fill: 0xffffff,
      fontFamily: "Oxanium, Opensans",
      fontSize: 15,
      fontWeight: "normal",
    };
    this.advancedBtnText.alignCenter();
    this.advancedBtnText.autoScaleToFit = true;
    this.advancedBtnText.boundaries = false;
    this.advancedBtnText.attachTo(this, "txt_btn_Advanced");

    this.basicBtnText = new TextAttachment({width: 70, height: 20}, this.options);
    this.basicBtnText.content = {key: "ui_autospins_basic"};
    this.basicBtnText.alignCenter();
    this.basicBtnText.style = {
      fill: 0xffffff,
      fontFamily: "Oxanium, Opensans",
      fontSize: 15,
      fontWeight: "normal",
    };
    this.basicBtnText.autoScaleToFit = true;
    this.basicBtnText.boundaries = false;
    this.basicBtnText.attachTo(this, "txt_btn_Basic");

    this.stopAutospinsTitleText = new TextAttachment({width: 300, height: 24}, this.options);
    this.stopAutospinsTitleText.content = {key: "ui_autospins_stop_autospin"};
    this.stopAutospinsTitleText.style = {
      fill: 0xffffff,
      fontFamily: "Oxanium, Opensans",
      fontSize: 20,
      fontWeight: "normal",
    };
    this.stopAutospinsTitleText.autoScaleToFit = true;
    this.stopAutospinsTitleText.boundaries = false;
    this.stopAutospinsTitleText.attachTo(this, "txt_Stop_autospin");

    this.numberOfRoundsTitleText = new TextAttachment({width: 300, height: 24}, this.options);
    this.numberOfRoundsTitleText.content = {key: "ui_autospins_numbers_of_rounds"};
    this.numberOfRoundsTitleText.style = {
      fill: 0xffffff,
      fontFamily: "Oxanium, Opensans",
      fontSize: 20,
      fontWeight: "normal",
    };
    this.numberOfRoundsTitleText.autoScaleToFit = true;
    this.numberOfRoundsTitleText.boundaries = false;
    this.numberOfRoundsTitleText.attachTo(this, "txt_Numbers of rounds");

    this.onAnyWinText = new TextAttachment({width: 190, height: 22}, this.options);
    this.onAnyWinText.content = {key: "ui_autospins_on_any_win"};
    this.onAnyWinText.style = {
      fill: 0xffffff,
      fontFamily: "Oxanium, Opensans",
      fontSize: 15,
      fontWeight: "lighter",
      letterSpacing: -1
    };
    this.onAnyWinText.autoScaleToFit = false;
    this.onAnyWinText.boundaries = false;
    this.onAnyWinText.attachTo(this, "txt_On any win");

    this.ifBonusGameWonText = new TextAttachment({width: 250, height: 22}, this.options);
    this.ifBonusGameWonText.content = {key: "ui_autospins_if_bonus_won"};
    this.ifBonusGameWonText.style = {
      fill: 0xffffff,
      fontFamily: "Oxanium, Opensans",
      fontSize: 15,
      fontWeight: "lighter",
      letterSpacing: -1
    };
    this.ifBonusGameWonText.autoScaleToFit = false;
    this.ifBonusGameWonText.alignCenter();
    this.ifBonusGameWonText.boundaries = false;
    this.ifBonusGameWonText.attachTo(this, "txt_If bonus game is won");

    this.ifSingleWinText = new TextAttachment({width: 190, height: 44}, this.options);
    this.ifSingleWinText.content = {key: "ui_autospins_if_single_win"};
    this.ifSingleWinText.style = {
      fill: 0xffffff,
      fontFamily: "Oxanium, Opensans",
      fontSize: 15,
      fontWeight: "lighter",
      letterSpacing: -1,
      wordWrap: true,
      wordWrapWidth: 200,
    };
    this.ifSingleWinText.autoScaleToFit = false;
    this.ifSingleWinText.boundaries = false;
    this.ifSingleWinText.alignCenter();
    this.ifSingleWinText.attachTo(this, "txt_If single win exceeds");
    this.ifSingleWinText.update();

    this.ifIncreasesText = new TextAttachment({width: 190, height: 22}, this.options);
    this.ifIncreasesText.content = {key: "ui_autospins_if_increases"};
    this.ifIncreasesText.style = {
      fill: 0xffffff,
      fontFamily: "Oxanium, Opensans",
      fontSize: 15,
      fontWeight: "lighter",
      letterSpacing: -1
    };
    this.ifIncreasesText.autoScaleToFit = true;
    this.ifIncreasesText.boundaries = false;
    this.ifIncreasesText.attachTo(this, "txt_If cash balance increases by");
    this.ifIncreasesText.update();

    this.ifDecreasesText = new TextAttachment({width: 190, height: 22}, this.options);
    this.ifDecreasesText.content = {key: "ui_autospins_if_decreases"};
    this.ifDecreasesText.style = {
      fill: 0xffffff,
      fontFamily: "Oxanium, Opensans",
      fontSize: 15,
      fontWeight: "lighter",
      letterSpacing: -1
    };
    this.ifDecreasesText.autoScaleToFit = true;
    this.ifDecreasesText.boundaries = false;
    this.ifDecreasesText.attachTo(this, "txt_If cash balance decreases by");
    this.ifDecreasesText.update();
  }

  parseTextFieldValue(value) {
    const [integer, decimal] = value.split(".");
    return decimal
      ? `${integer}${decimal ? "." + decimal.slice(0, this.inputs.currency.subunitsLength) : ""}`
      : value;
  }
}

// =============================
// States
// =============================

class BasicSettingsState extends State {
  constructor(window) {
    super("BasicSettingsState");
    this.window = window;
  }

  enter() {
    this.window.setBasicMode();
  }

  handleInput(input) {
    if (input) {
      this.window.setSettingsMode(SETTINGS_MODES.ADVANCED);
    }
  }
}

class AdvancedSettingsState extends State {
  constructor(window) {
    super("AdvancedSettingsState");
    this.window = window;
  }

  enter() {
    this.window.setAdvancedMode();
  }

  handleInput(input) {
    if (!input) {
      this.window.setSettingsMode(SETTINGS_MODES.BASIC);
    }
  }
}

class HiddenState extends State {
  constructor(window) {
    super("HiddenState");
    this.window = window;
  }

  enter() {
    this.window.hide();
  }

  handleInput(input) {
    if (input) {
      this.window.setDisplayingState(DISPLAYING_STATES.SHOWN);
    }
  }
}

class ShownState extends State {
  constructor(window) {
    super("ShownState");
    this.window = window;
  }

  enter() {
    this.window.show();
  }

  handleInput(input) {
    if (!input) {
      this.window.setDisplayingState(DISPLAYING_STATES.HIDDEN);
    }
  }
}
