import { useEffect, useRef } from "react";
import * as THREE from "three";

// Full-screen quad trick — bypasses the camera entirely
const VERT = /* glsl */ `
  varying vec2 vUv;
  void main() {
    vUv = uv;
    gl_Position = vec4(position.xy, 0.0, 1.0);
  }
`;

// Gradient-noise FBM fire shader
// vUv.y = 0 at screen bottom, 1 at screen top (Three.js PlaneGeometry convention)
const FRAG = /* glsl */ `
  uniform float uTime;
  uniform float uIntensity; // 0–1
  uniform float uAspect;
  varying vec2 vUv;

  // Gradient noise ─────────────────────────────────────────────────────
  vec2 hash2(vec2 p) {
    p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
    return -1.0 + 2.0 * fract(sin(p) * 43758.5453);
  }
  float noise(vec2 p) {
    vec2 i = floor(p);
    vec2 f = fract(p);
    vec2 u = f * f * (3.0 - 2.0 * f);
    return mix(
      mix(dot(hash2(i),           f),
          dot(hash2(i+vec2(1,0)), f-vec2(1,0)), u.x),
      mix(dot(hash2(i+vec2(0,1)), f-vec2(0,1)),
          dot(hash2(i+vec2(1,1)), f-vec2(1,1)), u.x),
      u.y);
  }
  float fbm(vec2 p) {
    float v = 0.0;
    v += 0.5000 * noise(p); p = p * 2.03 + vec2(0.31, 0.12);
    v += 0.2500 * noise(p); p = p * 1.97 + vec2(0.24, 0.35);
    v += 0.1250 * noise(p); p = p * 2.01 + vec2(0.17, 0.28);
    v += 0.0625 * noise(p);
    return v / 0.9375;
  }

  // Fire colour ramp: black → dark red → orange → yellow → pale yellow
  vec3 fireRamp(float t) {
    t = clamp(t, 0.0, 1.0);
    vec3 c0 = vec3(0.00, 0.00, 0.00);
    vec3 c1 = vec3(0.65, 0.04, 0.00);
    vec3 c2 = vec3(1.00, 0.28, 0.00);
    vec3 c3 = vec3(1.00, 0.76, 0.05);
    vec3 c4 = vec3(1.00, 1.00, 0.55);
    if (t < 0.25) return mix(c0, c1, t * 4.0);
    if (t < 0.50) return mix(c1, c2, (t - 0.25) * 4.0);
    if (t < 0.75) return mix(c2, c3, (t - 0.50) * 4.0);
    return           mix(c3, c4, (t - 0.75) * 4.0);
  }

  void main() {
    // How tall the fire reaches (fraction of screen height)
    float fireH = 0.28 + uIntensity * 0.24; // 0.28–0.52

    // Normalised height inside fire zone (0=ground, 1=top of flames)
    float yN = vUv.y / fireH;

    // Discard pixels comfortably above the fire zone
    if (yN > 1.6) { gl_FragColor = vec4(0.0); return; }

    float t = uTime * 0.45;

    // Noise coords: aspect-corrected X, upward-scrolling Y
    vec2 p = vec2(vUv.x * uAspect * 1.6, vUv.y / fireH * 1.4 - t);

    // Layered FBM — coarse structure + fine flicker
    float n  = fbm(p * 1.8);
    n += 0.55 * fbm(p * 3.6 + vec2(t * 0.25, 0.0));
    n += 0.20 * fbm(p * 7.0 - vec2(0.0, t * 0.6));
    n /= 1.75;

    // Vary flame height horizontally for ragged top edge
    float crest = 0.25 * noise(vec2(vUv.x * uAspect * 2.0 + t * 0.18, 0.3));
    float yMod  = yN + crest;

    // Core fire value
    float fire = (1.0 - yMod) * 1.1 + n * 0.75 - 0.05;
    fire *= 1.0 + uIntensity * 0.35;
    fire = clamp(fire, 0.0, 1.0);

    // Soft edge fade at left/right screen edges
    float edge = smoothstep(0.0, 0.07, vUv.x) * smoothstep(1.0, 0.93, vUv.x);
    fire *= 0.72 + edge * 0.28;

    vec3  col   = fireRamp(fire);
    float alpha = fire * fire; // quadratic → softer halo falloff

    gl_FragColor = vec4(col * alpha, alpha);
  }
`;

interface Props {
  active: boolean;
  intensity: number; // 0–100
}

export default function ThreeFireOverlay({ active, intensity }: Props) {
  const canvasRef = useRef<HTMLCanvasElement>(null);

  useEffect(() => {
    if (!active || !canvasRef.current) return;

    const canvas = canvasRef.current;
    const w = window.innerWidth;
    const h = window.innerHeight;

    const renderer = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: false });
    renderer.setClearColor(0x000000, 0);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    renderer.setSize(w, h, false);

    const scene  = new THREE.Scene();
    // Camera irrelevant for full-screen quad, but required by renderer
    const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);

    const uniforms = {
      uTime:      { value: 0 },
      uIntensity: { value: intensity / 100 },
      uAspect:    { value: w / h },
    };

    const material = new THREE.ShaderMaterial({
      uniforms,
      vertexShader:   VERT,
      fragmentShader: FRAG,
      transparent:    true,
      blending:       THREE.AdditiveBlending,
      depthTest:      false,
      depthWrite:     false,
    });

    const mesh = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), material);
    scene.add(mesh);

    let rafId: number;
    const startTime = performance.now();

    function animate() {
      rafId = requestAnimationFrame(animate);
      uniforms.uTime.value = (performance.now() - startTime) / 1000;
      renderer.render(scene, camera);
    }
    animate();

    function onResize() {
      const nw = window.innerWidth;
      const nh = window.innerHeight;
      renderer.setSize(nw, nh, false);
      uniforms.uAspect.value = nw / nh;
    }
    window.addEventListener("resize", onResize);

    return () => {
      cancelAnimationFrame(rafId);
      window.removeEventListener("resize", onResize);
      material.dispose();
      renderer.dispose();
    };
  }, [active, intensity]);

  if (!active) return null;

  return (
    <canvas
      ref={canvasRef}
      style={{
        position:      "fixed",
        top:           0,
        left:          0,
        width:         "100vw",
        height:        "100vh",
        pointerEvents: "none",
        zIndex:        9997,
      }}
    />
  );
}
