import {NumberField, StringField} from "@common/data/fields.mjs";
import VFXComponent from "../vfx-component.mjs";
import {VFXReferenceField} from "../fields/_module.mjs";

/**
 * @typedef VFXShakeData
 * @property {string} target           The canvas property key of the display object to shake (default "stage")
 * @property {number} duration         The active shake duration in milliseconds (default 5000)
 * @property {number} maxDisplacement  The maximum displacement in pixels at the start of the shake (default 35)
 * @property {number} returnSpeed      The return-to-origin interpolation factor per tick in [0, 1] (default 0.1)
 * @property {number|null} seed        An optional seed for a deterministic, reproducible shake pattern (default null)
 * @property {number} smoothness       Shake smoothness in [0, 1]; higher values produce lower-frequency motion (default 0.5)
 */

/**
 * A component that applies a canvas shake effect to a target PIXI display object using the
 * `CanvasShakeEffect` API. Primarily intended for camera shakes (`canvas.stage`) but can also
 * target individual canvas layers or groups.
 *
 * @example A screen shake on impact
 * ```js
 * const vfxConfig = {
 *   name: "impactShake",
 *   components: {
 *     screenShake: {
 *       type: "shake",
 *       target: "stage",
 *       duration: 800,
 *       maxDisplacement: 18,
 *       smoothness: 0.4
 *     }
 *   },
 *   timeline: [{component: "screenShake"}]
 * };
 * const effect = new foundry.canvas.vfx.VFXEffect(vfxConfig);
 * effect.play();
 * ```
 * @extends {VFXComponent<VFXShakeData>}
 */
export default class VFXShakeComponent extends VFXComponent {

  /** @override */
  static TYPE = "shake";

  /** @inheritDoc */
  static defineSchema() {
    return {
      ...super.defineSchema(),
      duration: new NumberField({required: true, nullable: false, initial: 5000, positive: true}),
      maxDisplacement: new NumberField({required: true, nullable: false, initial: 35, positive: true}),
      returnSpeed: new NumberField({required: true, nullable: false, initial: 0.1, min: 0, max: 1}),
      seed: new NumberField({initial: null}),
      smoothness: new NumberField({required: true, nullable: false, initial: 0.5, min: 0, max: 1}),
      target: new VFXReferenceField(new StringField({required: true, blank: false, initial: "stage"}))
    };
  }

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

  /**
   * The active CanvasShakeEffect instance, populated when the shake is triggered.
   * @type {foundry.canvas.animation.CanvasShakeEffect|null}
   */
  #shake = null;

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

  /** @override */
  async _draw() {
    this.timeline.call(() => {
      const target = canvas[this.target];
      if ( !target ) {
        console.warn(`VFXShakeComponent: canvas["${this.target}"] is not a valid shake target.`);
        return;
      }
      this.#shake = new foundry.canvas.animation.CanvasShakeEffect({
        duration: this.duration,
        maxDisplacement: this.maxDisplacement,
        returnSpeed: this.returnSpeed,
        seed: this.seed,
        smoothness: this.smoothness,
        target
      });
      this.#shake.play();
    }, 0);
    this.timeline.label("end", this.duration);
  }

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

  /** @override */
  async _stop() {
    this.#shake?.stop();
  }
}
