/**
 * LANE-RENDER — cooling aura footprint.
 *
 * `coolRadius` is CHEBYSHEV distance from the machine's footprint, so the region it
 * actually cools is a RECTANGLE — the footprint grown by r tiles on every side. Drawing
 * a circle here would be prettier and would lie: the corners it left out are cooled, and
 * players would plan around a boundary that isn't real. So this is a rectangle, aligned
 * to the grid it's actually measured in.
 *
 * Engineering-drawing vibe, not a buff circle: a thin dashed outline with tick marks at
 * the tile grid, no fill, no bloom. It's a coverage annotation, not a power-up.
 */
import * as THREE from 'three';

const AURA = 0x7fd4ff;

const VERT = /* glsl */ `
  varying vec2 vUv;
  void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }
`;

const FRAG = /* glsl */ `
  precision highp float;
  uniform vec2 uSize;    // rectangle size in TILES, so dashes stay tile-sized at any scale
  uniform vec3 uColor;
  uniform float uTime;
  varying vec2 vUv;

  void main() {
    vec2 p = vUv * uSize;              // position in tiles from the corner
    vec2 d = min(p, uSize - p);        // distance to the nearest edge, in tiles
    float edge = min(d.x, d.y);

    // Dashed border: march the dash phase around the perimeter, not across the face,
    // so corners don't smear.
    float along = (d.x < d.y) ? p.y : p.x;
    float dash = step(0.35, fract(along * 1.5 - uTime * 0.25));
    float line = (1.0 - smoothstep(0.03, 0.07, edge)) * dash;

    // Tick marks every tile, just inside the border — the drafting touch.
    float tick = step(0.94, fract(along)) * (1.0 - smoothstep(0.10, 0.16, edge));

    float a = max(line, tick * 0.7);
    if (a < 0.02) discard;
    gl_FragColor = vec4(uColor, a * 0.55);
  }
`;

export class CoolAura {
  readonly group = new THREE.Group();
  private mesh: THREE.Mesh;
  private uniforms = {
    uSize: { value: new THREE.Vector2(1, 1) },
    uColor: { value: new THREE.Color(AURA) },
    uTime: { value: 0 },
  };

  constructor() {
    this.group.name = 'coolAura';
    this.group.visible = false;
    this.mesh = new THREE.Mesh(
      new THREE.PlaneGeometry(1, 1),
      new THREE.ShaderMaterial({
        uniforms: this.uniforms,
        vertexShader: VERT,
        fragmentShader: FRAG,
        transparent: true,
        depthWrite: false,
      }),
    );
    this.mesh.rotation.x = -Math.PI / 2;
    this.mesh.position.y = 0.03;
    this.mesh.renderOrder = 9;
    this.group.add(this.mesh);
  }

  hide(): void {
    this.group.visible = false;
  }

  /**
   * `cx`/`cz` centre the machine; `fw`/`fd` are its ROTATED footprint; `r` is coolRadius.
   * Covered region = footprint + r tiles on each side (chebyshev).
   */
  show(cx: number, cz: number, fw: number, fd: number, r: number, timeSec: number): void {
    const w = fw + r * 2;
    const d = fd + r * 2;
    this.group.visible = true;
    this.uniforms.uSize.value.set(w, d);
    this.uniforms.uTime.value = timeSec;
    this.mesh.scale.set(w, d, 1);
    this.mesh.position.set(cx, 0.03, cz);
  }
}
