// post.js — ACES tonemap + bloom + vignette/grain composer.
import * as THREE from 'three';
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js';
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass.js';

// Final-stage vignette + film grain + subtle chromatic edge. Runs after tonemap.
const GrainVignetteShader = {
  uniforms: {
    tDiffuse: { value: null },
    uTime: { value: 0 },
    uVignette: { value: 1.05 },
    uGrain: { value: 0.05 },
    uAberration: { value: 0.0016 },
  },
  vertexShader: /* glsl */`
    varying vec2 vUv;
    void main(){ vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); }
  `,
  fragmentShader: /* glsl */`
    varying vec2 vUv;
    uniform sampler2D tDiffuse;
    uniform float uTime, uVignette, uGrain, uAberration;
    float hash(vec2 p){ return fract(sin(dot(p, vec2(127.1,311.7))) * 43758.5453); }
    void main(){
      vec2 uv = vUv;
      vec2 d = uv - 0.5;
      // chromatic aberration toward edges
      float r = texture2D(tDiffuse, uv + d * uAberration).r;
      float g = texture2D(tDiffuse, uv).g;
      float b = texture2D(tDiffuse, uv - d * uAberration).b;
      vec3 col = vec3(r, g, b);
      // vignette
      float vig = smoothstep(1.25, uVignette - 0.55, length(d) * 2.0);
      col *= mix(0.62, 1.0, vig);
      // film grain
      float n = hash(uv * vec2(1920.0, 1080.0) + fract(uTime) * 100.0);
      col += (n - 0.5) * uGrain;
      gl_FragColor = vec4(col, 1.0);
    }
  `,
};

export class Post {
  constructor(renderer, scene, camera) {
    this.renderer = renderer;
    this.composer = new EffectComposer(renderer);
    this.renderPass = new RenderPass(scene, camera);
    this.composer.addPass(this.renderPass);

    const size = renderer.getSize(new THREE.Vector2());
    this.bloom = new UnrealBloomPass(size, 0.7, 0.72, 0.78);
    this.composer.addPass(this.bloom);

    this.grain = new ShaderPass(GrainVignetteShader);
    this.composer.addPass(this.grain);

    this.output = new OutputPass();
    this.composer.addPass(this.output);
  }

  setScene(scene, camera) {
    this.renderPass.scene = scene;
    this.renderPass.camera = camera;
  }

  // tune bloom per mode
  configure({ strength, radius, threshold }) {
    if (strength != null) this.bloom.strength = strength;
    if (radius != null) this.bloom.radius = radius;
    if (threshold != null) this.bloom.threshold = threshold;
  }

  setSize(w, h) {
    this.composer.setSize(w, h);
    this.bloom.setSize(w, h);
  }

  render(dt) {
    this.grain.uniforms.uTime.value += dt;
    this.composer.render(dt);
  }
}
