import EffectMappingForm from '../applications/effectMappingForm.js';
import { OverlayConfig } from '../applications/overlayConfig.js';
import { TVAOverlay } from './sprite/TVAOverlay.js';
import { evaluateOverlayExpressions } from './token/overlay.js';

export class Reticle {
  static app;
  static fields;
  static reticleOverlay;
  static active = false;
  static hitTest;
  static token = null;
  static dialog = null;

  // Offset calculation controls
  static mode = 'tooltip';
  static increment = 1;

  static _onReticleMove(event) {
    if (this.reticleOverlay.isMouseDown) {
      let pos = event.data.getLocalPosition(this.reticleOverlay);

      this.config.pOffsetX = 0;
      this.config.pOffsetY = 0;
      this.config.offsetX = 0;
      this.config.offsetY = 0;

      if (this.mode === 'token') {
        this.config.linkRotation = true;
        this.config.linkMirror = true;
      }

      this.tvaOverlay.refresh(this.config, { preview: true });

      const tCoord = { x: this.tvaOverlay.x, y: this.tvaOverlay.y };

      if (this.tvaOverlay.overlayConfig.parentID) {
        let parent = this.tvaOverlay;
        do {
          parent = parent.parent;
          tCoord.x += parent.x;
          tCoord.y += parent.y;
        } while (!(parent instanceof TVAOverlay));
      }

      let dx = pos.x - tCoord.x;
      let dy = pos.y - tCoord.y;

      let angle = 0;
      if (!this.config.animation.relative) {
        angle = this.config.angle;
        if (this.config.linkRotation) angle += this.tvaOverlay.object.document.rotation;
      }

      [dx, dy] = rotate(0, 0, dx, dy, angle);
      dx = round(dx, this.increment);
      dy = round(dy, this.increment);

      // let lPos = event.data.getLocalPosition(this.tvaOverlay);
      // console.log(lPos);
      // // let dx = lPos.x;
      // // let dy = lPos.y;

      if (this.mode === 'static') {
        this.config.pOffsetX = dx;
        this.config.pOffsetY = dy;
      } else if (this.mode === 'token') {
        this.config.offsetX = -dx / this.tvaOverlay.object.w;
        this.config.offsetY = -dy / this.tvaOverlay.object.h;
      } else {
        let token = this.tvaOverlay.object;

        let pWidth;
        let pHeight;

        if (this.tvaOverlay.overlayConfig.parentID) {
          pWidth =
            (this.tvaOverlay.parent.shapesWidth ?? this.tvaOverlay.parent.width) / this.tvaOverlay.parent.scale.x;
          pHeight =
            (this.tvaOverlay.parent.shapesHeight ?? this.tvaOverlay.parent.height) / this.tvaOverlay.parent.scale.y;
        } else {
          pWidth = token.w;
          pHeight = token.h;
        }

        if (this.mode === 'tooltip') {
          if (Math.abs(dx) >= pWidth / 2) {
            this.config.offsetX = 0.5 * (dx < 0 ? 1 : -1);
            dx += (pWidth / 2) * (dx < 0 ? 1 : -1);
          } else {
            this.config.offsetX = -dx / this.tvaOverlay.object.w;
            dx = 0;
          }

          if (Math.abs(dy) >= pHeight / 2) {
            this.config.offsetY = 0.5 * (dy < 0 ? 1 : -1);
            dy += (pHeight / 2) * (dy < 0 ? 1 : -1);
          } else {
            this.config.offsetY = -dy / this.tvaOverlay.object.h;
            dy = 0;
          }
        } else {
          if (Math.abs(dx) >= pWidth / 2) {
            this.config.offsetX = 0.5 * (dx < 0 ? 1 : -1);
            dx += (pWidth / 2) * (dx < 0 ? 1 : -1);
          } else if (Math.abs(dy) >= pHeight / 2) {
            this.config.offsetY = 0.5 * (dy < 0 ? 1 : -1);
            dy += (pHeight / 2) * (dy < 0 ? 1 : -1);
          } else {
            this.config.offsetX = -dx / this.tvaOverlay.object.w;
            dx = 0;
            this.config.offsetY = -dy / this.tvaOverlay.object.h;
            dy = 0;
          }
        }

        this.config.pOffsetX = dx;
        this.config.pOffsetY = dy;
      }

      this.tvaOverlay.refresh(this.config, { preview: true });
    }
  }

  static minimizeApps() {
    Object.values(ui.windows).forEach((app) => {
      if (app instanceof OverlayConfig || app instanceof EffectMappingForm) {
        app.minimize();
      }
    });
  }

  static maximizeApps() {
    Object.values(ui.windows).forEach((app) => {
      if (app instanceof OverlayConfig || app instanceof EffectMappingForm) {
        app.maximize();
      }
    });
  }

  static activate({ tvaOverlay = null, config = {} } = {}) {
    if (this.deactivate() || !canvas.ready) return false;
    if (!tvaOverlay || !config) return false;

    if (this.reticleOverlay) {
      this.reticleOverlay.destroy(true);
    }

    const interaction = canvas.app.renderer.plugins.interaction;
    if (!interaction.cursorStyles['reticle']) {
      interaction.cursorStyles['reticle'] = "url('modules/token-variants/img/reticle.webp'), auto";
    }

    this.tvaOverlay = tvaOverlay;

    this.minimizeApps();
    this.config = evaluateOverlayExpressions(deepClone(config), this.tvaOverlay.object, {
      overlayConfig: config,
    });

    // Setup the overlay to be always visible while we're adjusting its position
    this.config.alwaysVisible = true;

    this.active = true;

    // Create the reticle overlay
    this.reticleOverlay = new PIXI.Container();
    this.reticleOverlay.hitArea = canvas.dimensions.rect;
    this.reticleOverlay.cursor = 'reticle';
    this.reticleOverlay.interactive = true;
    this.reticleOverlay.zIndex = Infinity;

    const stopEvent = function (event) {
      event.preventDefault();
      // event.stopPropagation();
    };

    this.reticleOverlay.on('mousedown', (event) => {
      event.preventDefault();

      if (event.data.originalEvent.which != 2 && event.data.originalEvent.nativeEvent.which != 2) {
        this.reticleOverlay.isMouseDown = true;
        this._onReticleMove(event);
      }
    });
    this.reticleOverlay.on('pointermove', (event) => {
      event.preventDefault();
      // event.stopPropagation();
      this._onReticleMove(event);
    });
    this.reticleOverlay.on('mouseup', (event) => {
      event.preventDefault();
      this.reticleOverlay.isMouseDown = false;
    });
    this.reticleOverlay.on('click', (event) => {
      event.preventDefault();
      if (event.data.originalEvent.which == 2 || event.data.originalEvent.nativeEvent.which == 2) {
        this.deactivate();
      }
    });

    canvas.stage.addChild(this.reticleOverlay);
    this.dialog = displayControlDialog();
    return true;
  }

  static deactivate() {
    if (this.active) {
      if (this.reticleOverlay) this.reticleOverlay.parent?.removeChild(this.reticleOverlay);
      this.active = false;
      this.tvaOverlay = null;
      if (this.dialog && this.dialog._state !== Application.RENDER_STATES.CLOSED) this.dialog.close(true);
      this.dialog = null;
      this.maximizeApps();

      const app = Object.values(ui.windows).find((app) => app instanceof OverlayConfig);
      if (!app) {
        this.config = null;
        return;
      }
      const form = $(app.form);

      ['pOffsetX', 'pOffsetY', 'offsetX', 'offsetY'].forEach((field) => {
        if (field in this.config) {
          form.find(`[name="${field}"]`).val(this.config[field]);
        }
      });

      if (this.mode === 'token') {
        ['linkRotation', 'linkMirror'].forEach((field) => {
          form.find(`[name="${field}"]`).prop('checked', true);
        });
        ['linkDimensionsX', 'linkDimensionsY'].forEach((field) => {
          form.find(`[name="${field}"]`).prop('checked', false);
        });
      } else {
        ['linkRotation', 'linkMirror'].forEach((field) => {
          form.find(`[name="${field}"]`).prop('checked', false);
        });
      }

      if (this.mode === 'hud') {
        form.find('[name="ui"]').prop('checked', true).trigger('change');
      }

      form.find('[name="anchor.x"]').val(this.config.anchor.x);
      form.find('[name="anchor.y"]').val(this.config.anchor.y).trigger('change');
      this.config = null;

      return true;
    }
  }
}

function displayControlDialog() {
  const d = new Dialog({
    title: 'Set Overlay Position',
    content: `
      <style>
        .images { display: flex; }
        .images a { flex: 20%; width: 50px; margin: 2px; }
        .images a.active img { border-color: orange; border-width: 2px; }
        .anchorlbl {margin: auto; display: table; }
      </style>
      <div class="images">
        <a data-id="token"><img src="modules/token-variants/img/token_mode.png"></img></a>
        <a data-id="tooltip"><img src="modules/token-variants/img/tooltip_mode.png"></img></a>
        <a data-id="hud"><img src="modules/token-variants/img/hud_mode.png"></img></a>
        <a data-id="static"><img src="modules/token-variants/img/static_mode.png"></img></a>
      </div>
     <br>
      <label class="anchorlbl">Anchor</label>
      <div class="tva-anchor">
        <input type="radio" class="top left" name="anchor">
        <input type="radio" class="top center" name="anchor">
        <input type="radio" class="top right" name="anchor">
        <input type="radio" class="mid left" name="anchor">
        <input type="radio" class="mid center" name="anchor">
        <input type="radio" class="mid right" name="anchor">
        <input type="radio" class="bot left" name="anchor">
        <input type="radio" class="bot center" name="anchor">
        <input type="radio" class="bot right" name="anchor">
      </div>
      <div class="form-group">
        <label>Step Size</label>
        <div class="form-fields">
          <input type="number" name="step" min="0" step="1" value="${Reticle.increment}">
        </div>
      </div>
      <p class="notes"><b>Left-Click</b> to move the overlay</p>
      <p class="notes"><b>Middle-Click</b> or <b>Close Dialog</b> to exit overlay positioning</p>
     `,
    buttons: {},
    render: (html) => {
      // Mode Images
      const images = html.find('.images a');
      html.find('.images a').on('click', (event) => {
        images.removeClass('active');
        const target = $(event.target).closest('a');
        target.addClass('active');
        Reticle.mode = target.data('id');
      });
      html.find(`[data-id="${Reticle.mode}"]`).addClass('active');

      // Anchor
      let anchorX = Reticle.config?.anchor?.x || 0;
      let anchorY = Reticle.config?.anchor?.y || 0;

      let classes = '';
      if (anchorX < 0.5) classes += '.left';
      else if (anchorX > 0.5) classes += '.right';
      else classes += '.center';

      if (anchorY < 0.5) classes += '.top';
      else if (anchorY > 0.5) classes += '.bot';
      else classes += '.mid';

      html.find('.tva-anchor').find(classes).prop('checked', true);
      // end -  Pre-select anchor

      html.find('input[name="anchor"]').on('change', (event) => {
        const anchor = $(event.target);
        let x;
        let y;
        if (anchor.hasClass('left')) x = 0;
        else if (anchor.hasClass('center')) x = 0.5;
        else x = 1;

        if (anchor.hasClass('top')) y = 0;
        else if (anchor.hasClass('mid')) y = 0.5;
        else y = 1;

        Reticle.config.anchor.x = x;
        Reticle.config.anchor.y = y;
      });

      html.find('[name="step"]').on('input', (event) => {
        Reticle.increment = $(event.target).val() || 1;
      });
    },
    close: () => Reticle.deactivate(),
  });
  d.render(true);
  setTimeout(() => d.setPosition({ left: 200, top: window.innerHeight / 2, height: 'auto' }), 100);
  return d;
}

function round(number, increment, offset = 0) {
  return Math.ceil((number - offset) / increment) * increment + offset;
}

function rotate(cx, cy, x, y, angle) {
  var radians = (Math.PI / 180) * angle,
    cos = Math.cos(radians),
    sin = Math.sin(radians),
    nx = cos * (x - cx) + sin * (y - cy) + cx,
    ny = cos * (y - cy) - sin * (x - cx) + cy;
  return [nx, ny];
}
