import { TMRUtility } from "../tmr-utility.js";
import { PixiTMR } from "./pixi-tmr.js";

const registeredEffects = [
]

/**
 * Définition des informations d'une "draconique" (queue, ombre, tête, souffle) qui influence les TMR
 */
export class Draconique {
  static isCaseTMR(element) { return element.type == 'casetmr'; }
  static isQueueDragon(element) { return element.type == 'queue' || element.type == 'ombre'; }
  static isSouffleDragon(element) { return element.type == 'souffle'; }
  static isTeteDragon(element) { return element.type == 'tete'; }
  static isQueueSouffle(it) { return Draconique.isQueueDragon(it) || Draconique.isSouffleDragon(it); }

  tmrLabel(linkData) { return TMRUtility.getTMRLabel(linkData.data.coord); }

  static register(draconique) {
    registeredEffects[draconique.code()] = draconique;
    if (draconique.img()) {
      PixiTMR.register(draconique.code(), draconique.img())
    }
    return draconique;
  }

  static all() {
    return Object.values(registeredEffects);
  }

  static get(code) {
    return registeredEffects[code];
  }

  /**
   * @param item un Item quelconque
   * @returns true si l'item correspond
   */
  match(item) {
    return Draconique.isQueueDragon(item) || Draconique.isSouffleDragon(item) || Draconique.isTeteDragon(item);
  }

  /**
   * @returns un message à afficher si la draconique doit être gérée manuellement.
   */
  manualMessage() {
    return false;
  }

  /**
   * Méthode responsable de gérer une draconique (par exemple, ajouter des casetmr pour la fermeture des cités).
   * @param actor auquel la draconique est ajoutée
   */
  async onActorCreateOwned(actor, item) {
    return false;
  }

  async onActorDeleteOwned(actor, item) {
    this.deleteCasesTmr(actor, item);
    return false;
  }

  async onActorDeleteCaseTmr(actor, casetmr) {
    return false;
  }
  /**
   * @return le code interne utilisé pour les casetmr correpondant
   */
  code() { return undefined }

  /**
   * @param {*} linkData données associées au token pixi (une casetmr, un sort en réserve, une rencontre en attente)
   * @returns un tooltip à afficher au dessus du token
   */
  tooltip(linkData) { return undefined }

  /**
   * @param {*} img l'url du fichier image à utiliser pour le token. Si indéfini (et si createSprite n'est pas surchargé),
   *  un disque est utilisé.
   */
  img() { return undefined }

  /**
   * factory d'élément graphique PIXI correpsondant à l'objet draconique
   * @param {*} pixiTMR instance de PixiTMR qui gère les tooltips, les méthodes de création de sprite standard, les clicks.
   */
  token(pixiTMR, linkData, coordTMR, type = undefined) {
    const token = {
      sprite: this.createSprite(pixiTMR),
      coordTMR: coordTMR
    };
    token[type ?? this.code()] = linkData;
    pixiTMR.addTooltip(token.sprite, this.tooltip(linkData));
    return token;

    return sprite;
  }
  /**
   * factory d'élément graphique PIXI correpsondant à l'objet draconique
   * @param {*} pixiTMR instance de PixiTMR qui gère les tooltips, les méthodes de création de sprite standard, les clicks.
   */
  createSprite(pixiTMR) {
    if (this.img()) {
      return pixiTMR.sprite(this.code());
    }
    else {
      return pixiTMR.circle()
    }
  }

  /**
   * 
   * @param {*} it un item à tester
   * @param {*} coord les coordonnées d'une case. Si undefined toute case du type correspondra, 
   */
  isCase(it, coord = undefined) {
    return Draconique.isCaseTMR(it) && it.data.specific == this.code() && (coord ? it.data.coord == coord : true);
  }

  find(list, coord = undefined) {
    return list.find(c => this.isCase(c, coord));
  }

  async createCaseTmr(actor, label, tmr, sourceId = undefined) {
    await actor.createOwnedItem({
      name: label, type: 'casetmr', img: this.img(), _id: randomID(16),
      data: { coord: tmr.coord, specific: this.code(), sourceid: sourceId }
    });
  }

  async deleteCasesTmr(actor, draconique) {
    let caseTmrs = actor.data.items.filter(it => this.isCase(it) && it.data.sourceid == draconique._id);
    for (let casetmr of caseTmrs) {
      await actor.deleteOwnedItem(casetmr._id);
    }
  }

  async onVisiteSupprimer(actor, tmr, onRemoveToken) {
    let existants = actor.data.items.filter(it => this.isCase(it, tmr.coord));
    for (let casetmr of existants) {
      await actor.deleteOwnedItem(casetmr._id);
      onRemoveToken(tmr, casetmr);
    }
  }
}