import {NumberField, StringField, SchemaField, AngleField} from "@common/data/fields.mjs";
import VFXReferenceField from "./vfx-reference-field.mjs";
import PointSourcePolygon from "../../geometry/shapes/source-polygon.mjs";
import * as fields from "@common/data/fields.mjs";

/**
 * A specialized VFX reference field that accepts either a pre-computed {@link PointSourcePolygon} instance
 * or a serializable configuration object {x, y, type, radius} sufficient to create one.
 *
 * In the serialized path, the field stores a plain config object and automatically computes the polygon
 * during field initialization. In the reference path, the field resolves to a live PointSourcePolygon
 * at runtime, allowing multiple components to share a single pre-computed polygon without redundant
 * computation.
 *
 * In both cases, the initialized value accessed by the component is always a PointSourcePolygon instance
 * (or null/undefined if not configured).
 *
 * @extends VFXReferenceField
 */
export default class VFXPointSourcePolygonField extends VFXReferenceField {
  constructor(options, context) {
    const schema = new SchemaField({
      type: new StringField({required: true, blank: false, initial: "move", choices: CONST.EDGE_RESTRICTION_TYPES}),
      x: new NumberField({required: true, nullable: false}),
      y: new NumberField({required: true, nullable: false}),
      elevation: new NumberField({required: false, nullable: true, initial: undefined}),
      level: new fields.DocumentIdField({readonly: false, initial: null}),
      radius: new NumberField({required: false, nullable: true, initial: null, positive: true}),
      angle: new AngleField({required: false, initial: undefined}),
      rotation: new AngleField({required: false, initial: undefined})
    }, {required: false, nullable: true, initial: null});
    super(schema, {nullable: true, initial: null, ...options}, context);
  }

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

  /** @override */
  _cleanType(value, options, state) {
    if ( value instanceof PointSourcePolygon ) return value;
    return super._cleanType(value, options, state);
  }

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

  /** @override */
  initialize(value, model, options) {
    if ( value instanceof PointSourcePolygon ) return value;
    if ( this.constructor.isReference(value) ) return undefined;
    if ( !value ) return value;
    const {x, y, elevation, ...config} = value;
    const origin = typeof elevation === "number" ? {x, y, elevation} : {x, y};
    config.level = config.level ? canvas.scene.levels.get(config.level) : canvas.level;
    return CONFIG.Canvas.polygonBackends[config.type].create(origin, config);
  }

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

  /** @override */
  _validateType(value, options) {
    if ( value instanceof PointSourcePolygon ) return;
    return super._validateType(value, options);
  }

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

  /** @override */
  resolve(value, references) {
    if ( !this.constructor.isReference(value) ) return this.valueField.clean(value);
    let result = references[value.reference];
    if ( value.property ) result = foundry.utils.getProperty(result, value.property);
    if ( result instanceof PointSourcePolygon ) return result;
    return this.valueField.clean(result);
  }
}
