import { Game } from "..";
import { System, SystemNames } from ".";
import { Miscellaneous, ModalClose, ModalOpen, SOUNDS } from "../config";
import { ComponentNames, Modal as ModalComponent } from "../components";
import { Entity } from "../entities";
import {
  CodeConsumer,
  CodeEditorInstance,
  CodeEditorSingleton,
  ModalInstance,
  ModalSingleton,
} from "../utils";

export interface ModalInitState {
  type: "CONTENT" | "CODE_EDITOR";
  contentInit?: {
    content: string;
  };
  codeInit?: {
    code: string;
    codeConsumer: CodeConsumer;
    readonly?: boolean;
    result?: { data?: string; error?: string };
  };
}

export class Modal extends System {
  private openingEntity: null | Entity = null;
  private modalInstance: ModalInstance = ModalSingleton;
  private codeEditorInstance: CodeEditorInstance = CodeEditorSingleton;

  constructor() {
    super(SystemNames.Modal);
  }

  public update(_dt: number, game: Game) {
    if (this.openingEntity) {
      if (this.openingEntity.hasComponent(ComponentNames.Modal)) {
        return;
      }
      this.closeCallback();
    }

    game.forEachEntityWithComponent(ComponentNames.Modal, (entity) => {
      const modalComponent = entity.getComponent<ModalComponent>(
        ComponentNames.Modal,
      );
      if (this.openingEntity) {
        return;
      }

      this.openingEntity = entity;
      SOUNDS.get(ModalOpen.name)!.play();

      if (modalComponent.initState.type === "CONTENT") {
        const content = `
          <div style="text-align:center"> 
            <div>${modalComponent.initState.contentInit!.content}</div>
            <br> 
            <button id="close">Close</button>
          </div>`;
        this.modalInstance.open(content);
        document
          .getElementById("close")
          ?.addEventListener("click", this.closeCallback.bind(this));
      }

      if (modalComponent.initState.type === "CODE_EDITOR") {
        this.codeEditorInstance.open(
          modalComponent.initState.codeInit!.code,
          (code) => {
            const result =
              modalComponent.initState.codeInit!.codeConsumer(code);
            if (result.consumed) {
              this.closeCallback();
            }
            return result;
          },
          !!modalComponent.initState.codeInit!.readonly,
          modalComponent.initState.codeInit!.result,
        );
      }
    });
  }

  private closeCallback() {
    this.openingEntity = null;
    this.modalInstance.vanish();
    this.codeEditorInstance.close();
    document.getElementById(Miscellaneous.CANVAS_ID)!.focus();
    SOUNDS.get(ModalClose.name)!.play();
  }
}
