import HackAttachment from "../HackAttachment.js";
import { Container, Graphics, Text } from "pixi.js";
import { gsap } from "gsap";
import Locator from "../../services/Locator";
import { tryToApplyFallbackFontFamily } from "../../utils/utils";

export default class EmbeddedTextField extends HackAttachment {
  constructor(spine, textFieldName, track, options) {
    super({ width: 60, height: 30 }, options);
    this.spine = spine;
    this.name = textFieldName;
    this.track = track;
    this.tween = null;
    this.boundaries = false;
    this.attachTo(this.spine, this.name + "_placeholder");
    this.setupInteractiveContainer();
    this.adjust();
    this.disable();
  }

  createContent() {
    this._wrapper = new Container();
    this.container.addChild(this._wrapper);
    this.textObject = new Text("", {
      fontFamily: "Oxanium, Opensans",
      fill: 0xffffff,
      fontWeight: 400,
      fontSize: 18,
      align: "left",
    });
    tryToApplyFallbackFontFamily(this.textObject);
    this.textObject.anchor.set(0, 0.5);
    this.textObject.resolution = this.texture.resolution;
    this._wrapper.addChild(this.textObject);

    this._cursor = new Graphics()
      .lineStyle(3, 0xffffff, 1, 1)
      .moveTo(0, -10)
      .lineTo(0, 10);
    this._cursor.alpha = 0;
    this._wrapper.addChild(this._cursor);

    this.input = document.createElement("input");
    this.input.type = "text";
    this.input.style.position = "absolute";
    this.input.style.opacity = "0";
    this.input.style.top = "0";
    this.input.style.zIndex = "-1";
    this.input.style.pointerEvents = "none";
    document.body.appendChild(this.input);
    this.input.addEventListener("keydown", (ev) => {
      switch (ev.key) {
      case "Enter":
        this.blur();
      case "ArrowUp":
      case "ArrowDown":
      case "ArrowLeft":
      case "ArrowRight":
      case "Tab":
      case "Esc":
        ev.preventDefault();
        break;
      default:
        break;
      }
    });

    const inputCallback = () => {
      let changed = false;
      if (this.textObject.text !== this.input.value && this.testString(this.input.value)) {
        changed = true;
      }

      if (changed) {
        this.textObject.text = this.input.value;

        this.emit("change", { name: this.name, value: this.textObject.text });
      } else {
        this.input.value = this.textObject.text;
      }
      this.adjust();
      this.update();
    };

    this.input.addEventListener("change", inputCallback);
    this.input.addEventListener("input", inputCallback);

    this._destroyInputs = () => {
      this.input.removeEventListener("change", inputCallback);
      this.input.removeEventListener("input", inputCallback);
      document.body.removeChild(this.input);
    }
  }

  setupInteractiveContainer() {
    const slotIndex = this.spine.skeleton.findSlotIndex(this.name);
    this.interactiveContainer = this.spine.slotContainers[slotIndex];
    this.interactiveContainer.eventMode = "none";
    Locator.events.on("globalpointerdown", this.globalPointerDownHandler, this);
    this.interactiveContainer.on("pointerdown", (e) => {
      this.focus();
      e.originalEvent.preventDefault();
      e.originalEvent.stopPropagation();
    });
  }

  disable() {
    this.isDisabled = true;
    this.spine.state.setAnimation(this.track, this.name + "/disable");
    this.interactiveContainer.eventMode = "none";
    this.tween && this.tween.kill();
    this.tween = null;
    this.input.blur();
    this._cursor.alpha = 0;
    this.update();
  }

  enable() {
    this.isDisabled = false;
    this.spine.state.setAnimation(this.track, this.name + "/blur");
    this.interactiveContainer.eventMode = "static";
    this._cursor.alpha = 0;
    this.update();
  }

  blur() {
    this.isDisabled = false;
    this.interactiveContainer.eventMode = "static";
    this.spine.state.setAnimation(this.track, this.name + "/blur");
    this.tween && this.tween.kill();
    this.tween = null;
    this._cursor.alpha = 0;
    this.input.blur();
    this.update();
  }

  focus() {
    this.isDisabled = false;
    this.interactiveContainer.eventMode = "static";
    this.spine.state.setAnimation(this.track, this.name + "/focus");
    this.input.focus();
    this.input.selectionStart = this.input.selectionEnd = this.input.value.length;
    this.createTween();
  }

  createTween() {
    if (this.tween) return;
    this.tween = gsap.to(this._cursor, { alpha: 1, duration: 0.1, yoyo: true, repeat: -1, repeatDelay: 0.4, ease: "none" })
      .eventCallback("onUpdate", () => {
        this.update();
      });
  }

  globalPointerDownHandler(e) {
    if (this.isDisabled) return;
    const target = Locator.renderer.events.rootBoundary.hitTest(e.global.x, e.global.y);
    if (target !== this.interactiveContainer) {
      this.blur();
    }
  }

  adjust() {
    this._wrapper.scale.set(1);
    const factor = Math.min(1, this.size.width / this._wrapper.width);
    this._cursor.x = this.textObject.width;
    this._wrapper.scale.set(factor);
    this._wrapper.position.set(
      (this.size.width - (this.textObject.width + this._cursor.width) * factor) * 0.5,
      this.size.height * 0.5
    );
  }

  testString(string) {
    const regex = /^\d*\.?\d{0,12}$/;
    return regex.test(string) && string.length <= 12;
  }

  clear() {
    this.textObject.text = "";
    this.input.value = "";
    this.adjust();
    this.update();
  }

  destroy() {
    super.destroy();
    this._destroyInputs();
    Locator.events.off("globalpointerdown", this.globalPointerDownHandler, this);
  }
}

