// scanner.js — scan pulse, world-space nameplates, discovery bookkeeping.
import * as THREE from 'three';

function nameplateTexture(item) {
  const w = 360, h = 132;
  const cv = document.createElement('canvas');
  cv.width = w; cv.height = h;
  const x = cv.getContext('2d');
  const isMin = item.type === 'mineral';
  const ac = isMin ? '#ffd27a' : '#65e8ff';
  // panel
  x.fillStyle = 'rgba(6,14,20,0.72)';
  roundRect(x, 8, 8, w - 16, h - 16, 10); x.fill();
  x.strokeStyle = ac; x.lineWidth = 2; x.globalAlpha = 0.9;
  roundRect(x, 8, 8, w - 16, h - 16, 10); x.stroke();
  x.globalAlpha = 1;
  // hex bullet
  x.fillStyle = ac;
  hexagon(x, 36, 44, 13); x.fill();
  // text
  x.fillStyle = '#eaffff';
  x.font = '600 30px "Segoe UI", system-ui, sans-serif';
  x.fillText(item.name, 60, 54);
  x.fillStyle = ac;
  x.font = '500 19px "Segoe UI", system-ui, sans-serif';
  x.fillText(isMin ? 'MINERAL' : 'FLORA', 60, 84);
  x.fillStyle = '#9fe9ff';
  x.font = '500 19px "Segoe UI", system-ui, sans-serif';
  x.fillText('+' + item.value + ' u', w - 90, 84);
  // tick line
  x.strokeStyle = ac; x.globalAlpha = 0.8; x.beginPath();
  x.moveTo(24, h - 22); x.lineTo(w - 24, h - 22); x.stroke();
  const tex = new THREE.CanvasTexture(cv);
  tex.anisotropy = 4;
  return tex;
}
function roundRect(x, px, py, w, h, r) {
  x.beginPath();
  x.moveTo(px + r, py);
  x.arcTo(px + w, py, px + w, py + h, r);
  x.arcTo(px + w, py + h, px, py + h, r);
  x.arcTo(px, py + h, px, py, r);
  x.arcTo(px, py, px + w, py, r);
  x.closePath();
}
function hexagon(x, cx, cy, r) {
  x.beginPath();
  for (let i = 0; i < 6; i++) {
    const a = (i / 6) * Math.PI * 2 + Math.PI / 6;
    const px = cx + Math.cos(a) * r, py = cy + Math.sin(a) * r;
    i ? x.lineTo(px, py) : x.moveTo(px, py);
  }
  x.closePath();
}

export class Scanner {
  constructor(scene) {
    this.scene = scene;
    this.active = false;
    this.radius = 0;
    this.maxR = 95;
    this.origin = new THREE.Vector3();
    this.plates = []; // {sprite, ring, item, life}

    // expanding pulse shell
    this.pulseMat = new THREE.ShaderMaterial({
      transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, side: THREE.DoubleSide,
      uniforms: { uColor: { value: new THREE.Color(0x6ff0ff) }, uOpacity: { value: 0 } },
      vertexShader: `varying vec3 vN; varying vec3 vV; void main(){ vN=normalize(normalMatrix*normal); vec4 mv=modelViewMatrix*vec4(position,1.0); vV=normalize(-mv.xyz); gl_Position=projectionMatrix*mv;}`,
      fragmentShader: `varying vec3 vN; varying vec3 vV; uniform vec3 uColor; uniform float uOpacity;
        void main(){ float f=pow(1.0-abs(dot(normalize(vN),normalize(vV))),3.5); gl_FragColor=vec4(uColor*(0.6+f), f*uOpacity);}`,
    });
    this.pulse = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 24), this.pulseMat);
    this.pulse.visible = false;
    this.pulse.frustumCulled = false;
    scene.add(this.pulse);

    // ground ring
    this.ringMat = new THREE.MeshBasicMaterial({ color: 0x6ff0ff, transparent: true, opacity: 0, blending: THREE.AdditiveBlending, side: THREE.DoubleSide, depthWrite: false });
    this.groundRing = new THREE.Mesh(new THREE.RingGeometry(0.9, 1, 64), this.ringMat);
    this.groundRing.rotation.x = -Math.PI / 2;
    this.groundRing.visible = false;
    scene.add(this.groundRing);
  }

  setColor(col) {
    this.pulseMat.uniforms.uColor.value.copy(col);
    this.ringMat.color.copy(col);
  }

  trigger(origin) {
    this.active = true;
    this.radius = 0;
    this.origin.copy(origin);
    this.pulse.visible = true;
    this.groundRing.visible = true;
    this.pulse.position.copy(origin);
  }

  // reveal a single item's nameplate immediately (used by scan sweep)
  reveal(item) {
    const tex = nameplateTexture(item);
    const sprite = new THREE.Sprite(new THREE.SpriteMaterial({ map: tex, transparent: true, depthTest: true, depthWrite: false }));
    sprite.scale.set(7.2, 2.64, 1);
    sprite.position.copy(item.pos).add(new THREE.Vector3(0, 2.2, 0));
    this.scene.add(sprite);
    // highlight ring at base
    const rmat = new THREE.MeshBasicMaterial({ color: item.type === 'mineral' ? 0xffd27a : 0x65e8ff, transparent: true, opacity: 0.85, blending: THREE.AdditiveBlending, depthWrite: false, side: THREE.DoubleSide });
    const ring = new THREE.Mesh(new THREE.RingGeometry(1.4, 1.8, 32), rmat);
    ring.rotation.x = -Math.PI / 2;
    ring.position.copy(item.pos).add(new THREE.Vector3(0, -1.4, 0));
    this.scene.add(ring);
    this.plates.push({ sprite, ring, item, life: 7.0 });
  }

  update(dt, scannables, onDiscover) {
    if (this.active) {
      this.radius += dt * 95;
      const r = this.radius;
      this.pulse.scale.setScalar(r);
      this.pulseMat.uniforms.uOpacity.value = THREE.MathUtils.clamp(1 - r / this.maxR, 0, 1) * 0.85;
      this.groundRing.position.set(this.origin.x, this.origin.y - 1.4, this.origin.z);
      this.groundRing.scale.setScalar(r);
      this.ringMat.opacity = THREE.MathUtils.clamp(1 - r / this.maxR, 0, 1) * 0.75;
      // reveal items as the wave passes them
      for (const item of scannables) {
        if (!item._revealed && item.pos.distanceTo(this.origin) <= r) {
          item._revealed = true;
          this.reveal(item);
          if (!item.scanned) { item.scanned = true; onDiscover && onDiscover(item); }
        }
      }
      if (r >= this.maxR) {
        this.active = false;
        this.pulse.visible = false;
        this.groundRing.visible = false;
        for (const item of scannables) item._revealed = false; // allow future re-pulse visuals
      }
    }
    // fade plates
    for (let i = this.plates.length - 1; i >= 0; i--) {
      const p = this.plates[i];
      p.life -= dt;
      const a = THREE.MathUtils.clamp(p.life / 1.5, 0, 1);
      p.sprite.material.opacity = a;
      p.ring.material.opacity = a * 0.85;
      p.ring.rotation.z += dt * 0.6;
      if (p.life <= 0) {
        this.scene.remove(p.sprite); this.scene.remove(p.ring);
        p.sprite.material.map.dispose(); p.sprite.material.dispose(); p.ring.material.dispose();
        this.plates.splice(i, 1);
      }
    }
  }

  clear() {
    for (const p of this.plates) {
      this.scene.remove(p.sprite); this.scene.remove(p.ring);
      p.sprite.material.map.dispose(); p.sprite.material.dispose(); p.ring.material.dispose();
    }
    this.plates = [];
    this.active = false;
    this.pulse.visible = false;
    this.groundRing.visible = false;
  }
}
