export class HTMLOverlay {
  static container = null;
  static renderQueue = [];
  static hudReady = false;

  static hudRendered() {
    HTMLOverlay.hudReady = true;
    HTMLOverlay.renderQueue.forEach((ov) => ov.render());
    HTMLOverlay.renderQueue = [];
  }

  constructor(overlayConfig, token) {
    this.overlayConfig = overlayConfig;
    this.token = token;
    this.render();
  }

  render(overlayConfig = null, force = false) {
    if (!HTMLOverlay.hudReady) {
      HTMLOverlay.renderQueue.push(this);
      return;
    }

    if (!HTMLOverlay.container) {
      HTMLOverlay.container = $('<div id="tva-html-overlays"></div>');
      $('#hud').append(HTMLOverlay.container);
    }

    if (this.element) this.remove();
    if (overlayConfig) this.overlayConfig = overlayConfig;

    this.element = $(renderTemplate(this.overlayConfig, this.getData(), force));
    HTMLOverlay.container.append(this.element);
    this.activateListeners(this.element);
    this.setPosition();
  }

  remove() {
    if (this.element) this.element.remove();
    this.element = null;
  }

  getData(options = {}) {
    const data = this.token.document.toObject();
    return foundry.utils.mergeObject(data, {
      isGM: game.user.isGM,
    });
  }

  setPosition({ left, top, width, height, scale, angle, origin } = {}) {
    if (!HTMLOverlay.hudReady) return;
    const ratio = canvas.dimensions.size / 100;
    const position = {
      width: width || this.token.document.width * 100,
      height: height || this.token.document.height * 100,
      left: left ?? this.token.document.x,
      top: top ?? this.token.document.y,
    };
    if (ratio !== 1) position.transform = `scale(${ratio})`;
    this.element.css(position);
    if (angle != null) {
      this.element.css({ transform: 'rotate(' + angle + 'deg)' });
    }
    if (origin != null) {
      this.element.css({ 'transform-origin': origin.x + 'px ' + origin.y + 'px' });
    }
  }

  /** @override */
  activateListeners(html) {
    try {
      eval(this.overlayConfig.html.listeners);
    } catch (e) {}
  }
}

const _templateCache = {};

function _compile(html, id) {
  //      <style scoped>${html.style}</style>
  return Handlebars.compile(
    `<div class="tva-html-overlay overlay-${id}">
      <section class="window-content">
        <form>${html.template}</form>
      </section>
    </div>`
  );
}

function constructTemplate(ovConfig, force = false) {
  if (!_templateCache.hasOwnProperty(ovConfig.id)) {
    const compiled = _compile(ovConfig.html, ovConfig.id);
    Handlebars.registerPartial(ovConfig.id, compiled);
    _templateCache[ovConfig.id] = compiled;
  } else if (force) {
    return _compile(ovConfig.html, ovConfig.id);
  }
  return _templateCache[ovConfig.id];
}

function renderTemplate(ovConfig, data, force = false) {
  const template = constructTemplate(ovConfig, force);
  return template(data || {}, {
    allowProtoMethodsByDefault: true,
    allowProtoPropertiesByDefault: true,
  });
}
