'use client';

/* eslint-disable @typescript-eslint/no-namespace */
import React, { useRef, useEffect } from 'react';
import { Canvas, useFrame, extend, useThree } from '@react-three/fiber';
import { shaderMaterial } from '@react-three/drei';
import * as THREE from 'three';
import { useBackground } from '../../context/BackgroundContext';
import { ColorPalette, PALETTES } from '../../types/theme';

// Module augmentation for R3F JSX elements
declare module 'react' {
  namespace JSX {
    interface IntrinsicElements {
      mesh: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & Record<string, unknown>;
      planeGeometry: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & Record<string, unknown>;
      fluidGradientMaterial: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & Record<string, unknown>;
    }
  }
}

// --- Custom Shader Material ---
// Archetype: "Fluid Flow" (Digital Sea)
// Advanced FBM Domain Warping with height-map color mixing and fluid interactivity.

const FluidGradientMaterial = shaderMaterial(
  {
    uTime: 0,
    uColorA: new THREE.Color("#DBEAFE"),
    uColorB: new THREE.Color("#E0E7FF"),
    uColorC: new THREE.Color("#F3E8FF"),
    uColorD: new THREE.Color("#E2E8F0"),
    uBackground: new THREE.Color("#f8fafc"),
    uMouse: new THREE.Vector2(0.5, 0.5),
    uResolution: new THREE.Vector2(1920, 1080),
    uDarkMode: 0.0,
    uAccent: new THREE.Color("#F59E0B"),
  },
  // Vertex Shader - Clean pass-through with subtle wave displacement
  `
    varying vec2 vUv;
    uniform float uTime;

    void main() {
      vUv = uv;
      
      // Subtle wave displacement for depth perception
      vec3 pos = position;
      float wave = sin(pos.x * 2.0 + uTime * 0.3) * cos(pos.y * 2.0 + uTime * 0.2) * 0.02;
      pos.z += wave;
      
      gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
    }
  `,
  // Fragment Shader - FBM Domain Warping with height-map color mixing
  `
    varying vec2 vUv;
    uniform float uTime;
    uniform vec3 uColorA;
    uniform vec3 uColorB;
    uniform vec3 uColorC;
    uniform vec3 uColorD;
    uniform vec3 uBackground;
    uniform vec3 uAccent;
    uniform vec2 uMouse;
    uniform vec2 uResolution;
    uniform float uDarkMode;

    // ============================================
    // NOISE FUNCTIONS - Ashima's Simplex Noise
    // ============================================
    vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
    vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
    vec3 permute(vec3 x) { return mod289(((x * 34.0) + 1.0) * x); }

    float snoise(vec2 v) {
      const vec4 C = vec4(0.211324865405187, 0.366025403784439,
                         -0.577350269189626, 0.024390243902439);
      vec2 i  = floor(v + dot(v, C.yy));
      vec2 x0 = v - i + dot(i, C.xx);
      vec2 i1;
      i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
      vec4 x12 = x0.xyxy + C.xxzz;
      x12.xy -= i1;
      i = mod289(i);
      vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0))
                       + i.x + vec3(0.0, i1.x, 1.0));
      vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy),
                              dot(x12.zw, x12.zw)), 0.0);
      m = m * m;
      m = m * m;
      vec3 x = 2.0 * fract(p * C.www) - 1.0;
      vec3 h = abs(x) - 0.5;
      vec3 ox = floor(x + 0.5);
      vec3 a0 = x - ox;
      m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);
      vec3 g;
      g.x = a0.x * x0.x + h.x * x0.y;
      g.yz = a0.yz * x12.xz + h.yz * x12.yw;
      return 130.0 * dot(m, g);
    }

    // ============================================
    // FRACTAL BROWNIAN MOTION (FBM)
    // ============================================
    float fbm(vec2 p) {
      float value = 0.0;
      float amplitude = 0.5;
      float frequency = 1.0;
      
      // 4 octaves for rich detail
      for (int i = 0; i < 4; i++) {
        value += amplitude * snoise(p * frequency);
        amplitude *= 0.5;
        frequency *= 2.0;
      }
      return value;
    }

    // ============================================
    // DOMAIN WARPING - The Magic Sauce
    // f(p) = fbm(p + fbm(p + fbm(p + uTime)))
    // ============================================
    float domainWarp(vec2 p, float time) {
      // First layer of warping
      vec2 q = vec2(
        fbm(p + vec2(0.0, 0.0)),
        fbm(p + vec2(5.2, 1.3))
      );
      
      // Second layer (nested warping for fluid effect)
      vec2 r = vec2(
        fbm(p + 4.0 * q + vec2(1.7, 9.2) + 0.15 * time),
        fbm(p + 4.0 * q + vec2(8.3, 2.8) + 0.126 * time)
      );
      
      return fbm(p + 4.0 * r);
    }

    // ============================================
    // BLEND MODES
    // ============================================
    vec3 blendScreen(vec3 base, vec3 blend) {
      return 1.0 - (1.0 - base) * (1.0 - blend);
    }

    vec3 blendSoftLight(vec3 base, vec3 blend) {
      return mix(
        sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend),
        2.0 * base * blend + base * base * (1.0 - 2.0 * blend),
        step(base, vec3(0.5))
      );
    }

    // ============================================
    // RANDOM (for grain/dithering)
    // ============================================
    float random(vec2 st) {
      return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
    }

    // ============================================
    // MAIN
    // ============================================
    void main() {
      // Aspect-ratio corrected UV
      vec2 uv = vUv;
      float aspect = uResolution.x / uResolution.y;
      vec2 p = (uv - 0.5) * vec2(aspect, 1.0);
      
      // Mouse influence - creates a "pull" in the fluid
      vec2 mouseOffset = (uMouse - 0.5) * 0.3;
      p += mouseOffset * smoothstep(1.0, 0.0, length(p - mouseOffset));
      
      // Time-based animation (slow, organic)
      float time = uTime * 0.8;
      
      // ============================================
      // DOMAIN WARPING - Generate height field
      // ============================================
      float warp = domainWarp(p * 1.2, time);
      
      // Normalize to 0-1 range (snoise returns -1 to 1)
      float height = warp * 0.5 + 0.5;
      
      // ============================================
      // HEIGHT-MAP COLOR MIXING
      // ============================================
      vec3 color;
      
      // Define height thresholds for color bands
      float t1 = 0.3;
      float t2 = 0.5;
      float t3 = 0.7;
      
      // Smooth interpolation between color bands
      if (height < t1) {
        // Low values: Background -> ColorA
        float t = smoothstep(0.0, t1, height);
        color = mix(uBackground, uColorA, t);
      } else if (height < t2) {
        // Mid-low values: ColorA -> ColorB
        float t = smoothstep(t1, t2, height);
        color = mix(uColorA, uColorB, t);
      } else if (height < t3) {
        // Mid-high values: ColorB -> ColorC
        float t = smoothstep(t2, t3, height);
        color = mix(uColorB, uColorC, t);
      } else {
        // High values (peaks): ColorC -> ColorD
        float t = smoothstep(t3, 1.0, height);
        color = mix(uColorC, uColorD, t);
      }
      
      // ============================================
      // DARK/LIGHT MODE BLENDING
      // ============================================
      if (uDarkMode > 0.5) {
        // Dark Mode: Deeper contrast, subtle glow on peaks
        color = mix(uBackground, color, 0.85);
        
        // Add accent glow on the highest peaks
        float peakGlow = smoothstep(0.75, 0.95, height);
        color = mix(color, uAccent, peakGlow * 0.25);
        
        // Subtle vignette for focus
        float vignette = 1.0 - smoothstep(0.3, 1.2, length(p));
        color *= 0.7 + 0.3 * vignette;
      } else {
        // Light Mode: Ethereal, airy, screen blending
        vec3 screenColor = blendScreen(uBackground, color);
        color = mix(uBackground, screenColor, 0.75);
        
        // Subtle accent shimmer on peaks
        float peakShimmer = smoothstep(0.7, 0.9, height);
        color = mix(color, blendSoftLight(color, uAccent), peakShimmer * 0.15);
        
        // Light vignette
        float vignette = 1.0 - smoothstep(0.5, 1.5, length(p));
        color *= 0.85 + 0.15 * vignette;
      }
      
      // ============================================
      // GRAIN/DITHERING (prevents banding)
      // ============================================
      float grainStrength = mix(0.02, 0.04, uDarkMode);
      float grain = (random(vUv * uTime * 0.01 + uTime) - 0.5) * grainStrength;
      color += grain;
      
      // Clamp to valid range
      color = clamp(color, 0.0, 1.0);
      
      gl_FragColor = vec4(color, 1.0);
    }
  `
);

extend({ FluidGradientMaterial });

// --- Scene Component ---

const GradientScene = ({ palette }: { palette: ColorPalette }) => {
  const materialRef = useRef<any>(null);
  const mouse = useRef(new THREE.Vector2(0.5, 0.5));
  const targetMouse = useRef(new THREE.Vector2(0.5, 0.5));
  const { viewport, size } = useThree();
  const { darkMode } = useBackground();

  // Smooth mouse tracking with heavy "fluid drag" effect
  useEffect(() => {
    const handleMouseMove = (e: MouseEvent) => {
      // Normalize mouse to 0-1 range
      targetMouse.current.set(
        e.clientX / window.innerWidth,
        1.0 - e.clientY / window.innerHeight
      );
    };
    window.addEventListener('mousemove', handleMouseMove);
    return () => window.removeEventListener('mousemove', handleMouseMove);
  }, []);

  useFrame((state, delta) => {
    if (!materialRef.current) return;

    // Update time
    materialRef.current.uTime += delta;

    // Update resolution
    materialRef.current.uResolution.set(size.width, size.height);

    // "Fluid Drag" - Heavy lerp for expensive, liquid feel
    const mouseLerp = 0.03; // Very slow = heavy fluid
    mouse.current.lerp(targetMouse.current, mouseLerp);
    materialRef.current.uMouse.copy(mouse.current);

    // Smooth dark mode transition
    const targetDarkMode = darkMode ? 1.0 : 0.0;
    materialRef.current.uDarkMode = THREE.MathUtils.lerp(
      materialRef.current.uDarkMode,
      targetDarkMode,
      delta * 2.5
    );

    // Smooth color transitions
    const colorLerp = delta * 1.5;
    materialRef.current.uColorA.lerp(new THREE.Color(palette.colorA), colorLerp);
    materialRef.current.uColorB.lerp(new THREE.Color(palette.colorB), colorLerp);
    materialRef.current.uColorC.lerp(new THREE.Color(palette.colorC), colorLerp);
    materialRef.current.uColorD.lerp(new THREE.Color(palette.colorD), colorLerp);
    materialRef.current.uBackground.lerp(new THREE.Color(palette.background), colorLerp);

    // Accent color based on mode
    const accentColor = darkMode
      ? new THREE.Color("#F59E0B") // Warm amber for dark
      : new THREE.Color("#FB7185"); // Rose for light
    materialRef.current.uAccent.lerp(accentColor, colorLerp);
  });

  return (
    <mesh scale={[viewport.width, viewport.height, 1]} position={[0, 0, 0]}>
      <planeGeometry args={[1, 1, 64, 64]} />
      <fluidGradientMaterial ref={materialRef} />
    </mesh>
  );
};

// --- Main Component ---

const GradientBackgroundBlackMagic = () => {
  const { currentTheme, darkMode } = useBackground();
  // Use PALETTES based on current section theme
  const activePalette = PALETTES[currentTheme][darkMode ? 'dark' : 'light'];

  return (
    <div className="relative h-full w-full overflow-hidden">
      <Canvas
        dpr={[1, 2]}
        camera={{ position: [0, 0, 1], fov: 50 }}
        gl={{
          antialias: false,
          alpha: true,
          powerPreference: "high-performance",
          stencil: false,
          depth: false,
        }}
      >
        <GradientScene palette={activePalette} />
      </Canvas>

      {/* Subtle noise texture overlay for tactile feel */}
      <div
        className="absolute inset-0 z-10 opacity-[0.02] pointer-events-none mix-blend-overlay"
        style={{
          backgroundImage: `url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E")`,
        }}
      />
    </div>
  );
};

export default GradientBackgroundBlackMagic;
