import DialogV2 from "../../applications/api/dialog.mjs";
import SceneControls from "../../applications/ui/scene-controls.mjs";
import PlaceablesLayer from "./base/placeables-layer.mjs";
import ShapeLayerMixin from "./mixins/shapes.mjs";
import AmbientLightPalette from "../../applications/sheets/palette/ambient-light-palette.mjs";

/**
 * The Lighting Layer which ambient light sources as part of the CanvasEffectsGroup.
 * @category Canvas
 */
export default class LightingLayer extends ShapeLayerMixin(PlaceablesLayer) {

  /** @inheritDoc */
  static documentName = "AmbientLight";

  /** @inheritdoc */
  static paletteClass = AmbientLightPalette;

  /** @inheritDoc */
  static get layerOptions() {
    return foundry.utils.mergeObject(super.layerOptions, {
      name: "lighting",
      controllableObjects: true,
      rotatableObjects: true,
      zIndex: 900
    });
  }

  /**
   * Darkness change event handler function.
   * @type {this["_onDarknessChange"]}
   */
  #onDarknessChange;

  /* -------------------------------------------- */

  /** @inheritDoc */
  get hookName() {
    return LightingLayer.name;
  }

  /* -------------------------------------------- */
  /*  Rendering                                   */
  /* -------------------------------------------- */

  /** @inheritDoc */
  async _draw(options) {
    await super._draw(options);
    this.#onDarknessChange = this._onDarknessChange.bind(this);
    canvas.environment.addEventListener("darknessChange", this.#onDarknessChange);
  }

  /* -------------------------------------------- */

  /** @inheritDoc */
  async _tearDown(options) {
    canvas.environment.removeEventListener("darknessChange", this.#onDarknessChange);
    this.#onDarknessChange = undefined;
    return super._tearDown(options);
  }

  /* -------------------------------------------- */
  /*  Methods                                     */
  /* -------------------------------------------- */

  /**
   * Refresh the fields of all the ambient lights on this scene.
   */
  refreshFields() {
    if ( !this.active ) return;
    for ( const ambientLight of this.placeables ) {
      ambientLight.renderFlags.set({refreshField: true});
    }
  }

  /* -------------------------------------------- */

  /** @inheritDoc */
  _activate() {
    super._activate();
    this.setAllRenderFlags({refreshField: true});
  }

  /* -------------------------------------------- */

  /** @override */
  static prepareSceneControls() {
    const sc = SceneControls;
    return {
      name: "lighting",
      order: 5,
      title: "CONTROLS.GroupLighting",
      layer: "lighting",
      icon: "fa-regular fa-lightbulb",
      visible: game.user.isGM,
      onChange: (event, active) => {
        if ( active ) canvas.lighting.activate();
      },
      onToolChange: (_event, tool, active) => {
        canvas.lighting.setAllRenderFlags({refreshState: true});
        if ( active && !tool.control ) canvas.lighting.releaseAll();
      },
      tools: {
        select: {
          name: "select",
          order: 1,
          title: "CONTROLS.LightSelect",
          icon: "fa-solid fa-expand",
          interaction: true,
          control: true,
          toolclip: {
            heading: "CONTROLS.LightSelect",
            items: sc.buildToolclipItems(["selectAlt", "selectMultiple", "move", "edit", "rotate", "delete"])
          }
        },
        light: {
          name: "light",
          order: 2,
          title: "CONTROLS.LightDraw",
          icon: "fa-solid fa-lightbulb",
          interaction: true,
          control: true,
          creation: true,
          toolclip: {
            heading: "CONTROLS.LightDraw",
            items: sc.buildToolclipItems(["create", "select", "edit", "rotate", "onOff"])
          }
        },
        day: {
          name: "day",
          order: 3,
          title: "CONTROLS.LightDay",
          icon: "fa-solid fa-sun",
          visible: !canvas.scene?.environment.darknessLock,
          onChange: () => canvas.scene.update(
            {environment: {darknessLevel: 0.0}},
            {animateDarkness: CONFIG.Canvas.darknessToDaylightAnimationMS}
          ),
          button: true,
          toolclip: {
            heading: "CONTROLS.LightDay",
            items: sc.buildToolclipItems([{heading: "CONTROLS.MakeDayH", content: "CONTROLS.MakeDayP"},
              {heading: "CONTROLS.AutoLightToggleH", content: "CONTROLS.AutoLightToggleP"}])
          }
        },
        night: {
          name: "night",
          order: 4,
          title: "CONTROLS.LightNight",
          icon: "fa-solid fa-moon",
          visible: !canvas.scene?.environment.darknessLock,
          onChange: () => canvas.scene.update(
            {environment: {darknessLevel: 1.0}},
            {animateDarkness: CONFIG.Canvas.daylightToDarknessAnimationMS}
          ),
          button: true,
          toolclip: {
            heading: "CONTROLS.LightNight",
            items: sc.buildToolclipItems([{heading: "CONTROLS.MakeNightH", content: "CONTROLS.MakeNightP"},
              {heading: "CONTROLS.AutoLightToggleH", content: "CONTROLS.AutoLightToggleP"}])
          }
        },
        reset: {
          name: "reset",
          order: 5,
          title: "CONTROLS.LightReset",
          icon: "fa-solid fa-cloud",
          onChange: () => {
            DialogV2.confirm({
              window: {title: "CONTROLS.FOWResetTitle", icon: "fa-solid fa-cloud"},
              content: `<p>${_loc("CONTROLS.FOWResetDesc")}</p>`,
              yes: {callback: () => canvas.fog.reset()}
            });
          },
          button: true,
          toolclip: {
            src: "toolclips/tools/light-reset.webm",
            heading: "CONTROLS.LightReset",
            items: [{paragraph: "CONTROLS.LightResetP"}]
          }
        },
        togglePalette: { ...this.TOGGLE_PALETTE, order: 6 },
        clear: {
          name: "clear",
          order: 7,
          title: "CONTROLS.LightClear",
          icon: "fa-solid fa-trash",
          onChange: () => canvas.lighting.deleteAll(),
          button: true
        }
      },
      activeTool: "select"
    };
  }

  /* -------------------------------------------- */
  /*  Event Listeners and Handlers                */
  /* -------------------------------------------- */

  /** @override */
  _createDragShapeData(event) {
    const angle = this.paletteCreateData.config?.angle;
    if ( angle < 360 ) return {type: "cone", x: 0, y: 0, radius: 0, angle, rotation: 0};
    return {type: "circle", x: 0, y: 0, radius: 0};
  }

  /* -------------------------------------------- */

  /** @override */
  _updateDragPreview(event) {
    const {shape, preview} = event.interactionData;
    const {x, y, radius} = shape;
    const dim = radius / canvas.dimensions.distancePixels;
    const bright = 0.5 * dim;
    const data = {x, y, config: {dim, bright}};
    if ( shape.type === "cone" ) {
      data.rotation = shape.rotation - 90;
      data.config.angle = shape.angle;
    }
    preview.document.updateSource(data);
    preview.renderFlags.set({refreshTransform: true, refreshField: true});
    preview.initializeLightSource();
  }

  /* -------------------------------------------- */

  /** @override */
  _updateMouseWheelPreview() {
    const {preview, shape} = this._mouseWheelContext;
    preview.document.updateSource({rotation: shape.rotation - 90});
    preview.renderFlags.set({refreshRotation: true, refreshField: true});
    preview.initializeLightSource();
  }

  /* -------------------------------------------- */

  /** @override */
  _onDragLeftCancel(event) {
    super._onDragLeftCancel(event);
    canvas.effects.refreshLighting();
  }

  /* -------------------------------------------- */

  /**
   * Actions to take when the darkness level of the Scene is changed
   * @param {PIXI.FederatedEvent} event
   * @internal
   */
  _onDarknessChange(event) {
    const {darknessLevel, priorDarknessLevel} = event.environmentData;
    for ( const light of this.placeables ) {
      const {min, max} = light.document.config.darkness;
      if ( darknessLevel.between(min, max) === priorDarknessLevel.between(min, max) ) continue;
      light.initializeLightSource();
      if ( this.active ) light.renderFlags.set({refreshState: true});
    }
  }
}
