import { Misc } from "../misc.js";
import { TMRConstants, tmrTokenZIndex } from "../tmr-constants.js";
import { TMRUtility } from "../tmr-utility.js";
import { EffetsDraconiques } from "./effets-draconiques.js";

export class PixiTMR {
  static textures = []

  static getImgFromCode(code) {
    return PixiTMR.textures[code]
  }

  static register(name, img) {
    PixiTMR.textures[name] = img;
  }

  static async init() {
    await Promise.all(
      Object.values(PixiTMR.textures)
        .filter(img => img != undefined && !PIXI.utils.TextureCache[img])
        .map(async img => PIXI.Sprite.from(await PIXI.Assets.load(img))))
  }

  constructor(tmrDialog, displaySize) {
    this.tmrDialog = tmrDialog;
    this.callbacksOnAnimate = [];
    this.sizes = new TMRConstants({ size: displaySize })
    console.info(`Creation d'Application PIXI pour les TMR de ${tmrDialog.actor.name}`)
    this.pixiApp = new PIXI.Application(PixiTMR.computeTMRSize(this.sizes));
    this.pixiApp.eventMode = 'static';
    this.pixiApp.stage.sortableChildren = true;

    this.tooltipStyle = new PIXI.TextStyle({
      fontFamily: 'CaslonAntique',
      fontSize: 16,
      fill: '#FFFFFF',
      stroke: '#000000',
      strokeThickness: 4
    });

    this.tooltip = new PIXI.Text('', this.tooltipStyle);
    this.tooltip.zIndex = 1000

    this.pixiApp.stage.addChild(this.tooltip);
  }

  close() {
    console.info(`Destruction d'Application PIXI pour les TMR de ${this.tmrDialog.actor.name}`)
    this.pixiApp.destroy();
    this.pixiApp = undefined
  }
  static computeTMRSize(sizeConstants) {
    return { width: sizeConstants.cellw * 13 + sizeConstants.marginx, height: sizeConstants.cellh / 2 + sizeConstants.cellh * 15 + sizeConstants.marginy }
  }

  resizeTMR(displaySize) {
    this.sizes = new TMRConstants({ size: displaySize })
    const appSize = PixiTMR.computeTMRSize(this.sizes)
    this.pixiApp.renderer.resize(appSize.width, appSize.height)
    this.tooltipStyle.fontSize = Math.max(this.sizes.size / 3, 16)
  }

  get view() {
    return this.pixiApp.view
  }

  setup() {
    this.carteTMR = EffetsDraconiques.carteTmr.createSprite(this);
    this.pixiApp.stage.addChild(this.carteTMR);
    this.carteTMR.isOver = false;
    this.carteTMR.eventMode = 'static';
    this.carteTMR
      .on('pointermove', event => this.onPointerMove(event))
      .on('pointerdown', event => this.onClickBackground(event))
      .on('pointerover', event => this.onShowTooltip(event))
      .on('pointerout', event => this.onHideTooltip(event));
  }

  async loadAnimations() {
    for (let onAnimate of this.callbacksOnAnimate) {
      onAnimate();
    }
    this.pixiApp.ticker.start();
  }

  animate(animation = pixiApp => { }) {
    this.callbacksOnAnimate.push(() => animation(this.pixiApp));
  }

  addMarkTMR(coordTMR) {
    const rect = this.getCaseRectangle(TMRUtility.coordTMRToOddq(coordTMR))
    const markTMR = new PIXI.Graphics();
    markTMR.beginFill(0xffff00, 0.3);
    // set the line style to have a width of 5 and set the color to red
    markTMR.lineStyle(5, 0xff0000);
    // draw a rectangle
    markTMR.drawRect(rect.x, rect.y, rect.w, rect.h);
    this.pixiApp.stage.addChild(markTMR);
    return markTMR
  }

  removeGraphic(graphic) {
    this.pixiApp.stage.removeChild(graphic);
  }

  sprite(code, options = {}) {
    let img = PixiTMR.getImgFromCode(code)
    let texture = PIXI.utils.TextureCache[img]
    if (!texture) {
      // TODO: charger la texture
      console.error("Texture manquante", code, PIXI.utils.TextureCache)
      return;
    }
    let sprite = new PIXI.Sprite(texture);
    sprite.taille = options.taille ?? (() => this.sizes.half)

    sprite.width = sprite.taille()
    sprite.height = sprite.taille()
    sprite.anchor.set(0.5)
    if (options.tint) {
      sprite.tint = options.tint
    }
    sprite.zIndex = options.zIndex ?? tmrTokenZIndex.casehumide + 1
    sprite.alpha = options.alpha ?? 1
    sprite.decallage = options.decallage ?? this.sizes.center
    this.pixiApp.stage.addChild(sprite)
    return sprite
  }

  circle(code, options = {}) {
    let sprite = new PIXI.Graphics()
    sprite.taille = options.taille ?? (() => this.sizes.half)
    sprite.decallage = options.decallage ?? this.sizes.topLeft
    sprite.beginFill(options.tint, options.opacity)
    sprite.drawCircle(0, 0, sprite.taille())
    sprite.endFill()
    this.pixiApp.stage.addChild(sprite)
    return sprite
  }

  square(code, options = {}) {
    let sprite = new PIXI.Graphics();
    sprite.taille = options.taille ?? (() => this.sizes.half)
    sprite.decallage = options.decallage ?? this.sizes.topLeft
    sprite.beginFill(options.tint, options.opacity)
    const size = sprite.taille();
    sprite.drawRect(0, 0, size, size)
    sprite.endFill()
    this.pixiApp.stage.addChild(sprite)
    return sprite
  }

  onClickBackground(event) {
    if (!this.viewOnly) {
      this.tmrDialog.onClickTMR(event)
    }
  }

  onPointerMove(event) {
    if (this.carteTMR.isOver) {
      this.setTooltipPosition(event);
      this.tooltip.text = this.computeTooltip(event);
    }
  }

  onShowTooltip(event) {
    if (!this.carteTMR.isOver) {
      this.setTooltipPosition(event);
      this.pixiApp.stage.addChild(this.tooltip);
      this.tooltip.text = this.computeTooltip(event);
    }
    this.carteTMR.isOver = true;
  }

  onHideTooltip(event) {
    if (this.carteTMR.isOver) {
      this.pixiApp.stage.removeChild(this.tooltip);
    }
    this.carteTMR.isOver = false;
  }

  computeTooltip(event) {
    const oddq = this.sizes.computeEventOddq(event);
    const coordTMR = TMRUtility.oddqToCoordTMR(oddq);
    const tmr = TMRUtility.getTMR(coordTMR)
    if (tmr) {
      const tmrTooltip = `${coordTMR}: ${TMRUtility.getTMRLabel(coordTMR)}`;
      const tokenTooltips = this.tmrDialog.allTokens
        .filter(token => token.coordTMR() == coordTMR)
        .map(token => token.tooltip);
      return [tmrTooltip, ...tokenTooltips].reduce(Misc.joining('\n'))
    }
  }

  computeEventOddq(event) {
    return this.sizes.computeEventOddq(event)
  }

  setTooltipPosition(event) {
    const oddq = this.sizes.computeEventOddq(event);

    this.tooltip.x = oddq.x + (oddq.col > 7 ? -2.5 * this.sizes.full : this.sizes.quarter);
    this.tooltip.y = oddq.y + (oddq.row > 10 ? -this.sizes.size : 0);
  }

  positionToken(token) {
    if (token.sprite) {
      const sprite = token.sprite;
      const oddq = TMRUtility.coordTMRToOddq(token.coordTMR());

      const decallagePairImpair = (oddq.col % 2 == 0) ? this.sizes.col1_y : this.sizes.col2_y;
      const dx = sprite.decallage?.x ?? 0
      const dy = sprite.decallage?.y ?? 0
      sprite.x = this.sizes.gridx + (oddq.col * this.sizes.cellw) + dx;
      sprite.y = this.sizes.gridy + (oddq.row * this.sizes.cellh) + dy + decallagePairImpair;
    }
  }

  removeToken(token) {
    if (token.sprite) {
      this.pixiApp.stage.removeChild(token.sprite)
    }
  }

  getCaseRectangle(oddq) {
    const decallagePairImpair = (oddq.col % 2 == 0) ? this.sizes.col1_y : this.sizes.col2_y;
    const x = this.sizes.gridx + (oddq.col * this.sizes.cellw) - (this.sizes.cellw / 2);
    const y = this.sizes.gridy + (oddq.row * this.sizes.cellh) - (this.sizes.cellh / 2) + decallagePairImpair;
    return { x, y, w: this.sizes.cellw, h: this.sizes.cellh };
  }
}