import { Color, Material, Mesh, Object3D, Vector3 } from "three";
import { ResourceScreenFly } from "../Resources/ResourceScreenFly";
import {
  findInteractiveZoneFromMap,
  getInteractiveZoneCenter,
  INTERACTIVE_ZONE_NAME,
} from "./MapInteractiveZone";

const FILL_TARGET = 10;
const FILL_COLOR = new Color(0x2db83a);

export class InteractiveZoneC {
  private static zoneRoot: Object3D | null = null;
  private static deposited = 0;
  private static baseColors = new WeakMap<Material, Color>();

  static init(mapObject: Object3D) {
    const zone = findInteractiveZoneFromMap(mapObject);
    if (!zone) {
      console.warn(`Interactive zone not found: ${INTERACTIVE_ZONE_NAME}`);
      return;
    }

    this.zoneRoot = zone;
    this.setupMaterials(zone);
  }

  static getWorldCenter(out = new Vector3()) {
    if (!this.zoneRoot) return out.set(0, 0, 0);
    return getInteractiveZoneCenter(this.zoneRoot, out);
  }

  static getScreenCenter() {
    return ResourceScreenFly.worldToScreen(this.getWorldCenter());
  }

  static addDeposit(amount = 1) {
    this.deposited += amount;
    this.refreshFillVisual();
  }

  static getFillRatio() {
    return Math.min(this.deposited / FILL_TARGET, 1);
  }

  private static setupMaterials(zone: Object3D) {
    zone.traverse((child) => {
      if (!(child as Mesh).isMesh) return;

      const mesh = child as Mesh;
      const sourceMaterial = mesh.material;
      if (Array.isArray(sourceMaterial)) return;

      if (!sourceMaterial) return;

      const cloned = sourceMaterial.clone();
      if ("color" in cloned) {
        this.baseColors.set(cloned, (cloned.color as Color).clone());
      }
      mesh.material = cloned;
    });

    this.refreshFillVisual();
  }

  private static refreshFillVisual() {
    if (!this.zoneRoot) return;

    const ratio = this.getFillRatio();

    this.zoneRoot.traverse((child) => {
      if (!(child as Mesh).isMesh) return;

      const material = (child as Mesh).material;
      if (Array.isArray(material) || !material) return;

      const baseColor = this.baseColors.get(material);
      if (!baseColor || !("color" in material)) return;

      (material.color as Color).copy(baseColor).lerp(FILL_COLOR, ratio);
    });
  }
}
