import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
import { useRef, useMemo, useEffect } from 'react';
import { Canvas, useFrame } from '@react-three/fiber';
import { Environment } from '@react-three/drei';
import { ACESFilmicToneMapping, Color, OneFactor, ZeroFactor, AddEquation, CustomBlending, BackSide } from 'three';
import { simplex3 } from './Liquid.noise.js';
import { atmosphereFragment, glowVertex } from './Liquid.shaders.js';
import { useOrbState } from '../../hooks/useOrbState.js';

const STATE_CONFIG = {
    idle: { speed: 0.5, noiseAmplitude: 0.06, glowIntensity: 0.6 },
    listening: { speed: 1.0, noiseAmplitude: 0.1, glowIntensity: 1.0 },
    thinking: { speed: 1.8, noiseAmplitude: 0.15, glowIntensity: 1.4 },
    speaking: { speed: 1.2, noiseAmplitude: 0.12, glowIntensity: 1.2 },
};
const LiquidScene = ({ colors, meshColor, speed, roughness, metalness, noiseScale, noiseAmplitude, glowIntensity, glowSize, state, }) => {
    const groupRef = useRef(null);
    const meshRef = useRef(null);
    const atmosphereRef = useRef(null);
    // Store original positions + normals for noise deformation
    const origData = useRef(null);
    // Keep latest props in a ref so useFrame always reads current values
    const propsRef = useRef({ speed, noiseScale, noiseAmplitude });
    propsRef.current = { speed, noiseScale, noiseAmplitude };
    // ── State-driven interpolation ─────────────────────────────────────────
    const stateProps = useMemo(() => ({ speed, noiseAmplitude, glowIntensity }), [speed, noiseAmplitude, glowIntensity]);
    const { valuesRef: stateRef, tick: stateTick } = useOrbState(state, STATE_CONFIG, stateProps);
    // Colour objects (rebuilt only when hex strings change)
    const [c1, c2, c3] = colors;
    const colorObjs = useMemo(() => ({
        c1: new Color(c1),
        c2: new Color(c2),
        c3: new Color(c3),
    }), [c1, c2, c3]);
    // ── Atmosphere uniforms – created once, mutated in useFrame / useEffect ────
    // Atmosphere: soft diffuse haze (BackSide)
    const atmosphereUniforms = useMemo(() => ({
        u_time: { value: 0 },
        u_color1: { value: new Color(c1) },
        u_color2: { value: new Color(c2) },
        u_color3: { value: new Color(c3) },
        u_intensity: { value: glowIntensity * 0.65 },
    }), 
    // eslint-disable-next-line react-hooks/exhaustive-deps
    []);
    // ── Capture original geometry on mount ───────────────────────────────────
    useEffect(() => {
        if (!meshRef.current)
            return;
        const geo = meshRef.current.geometry;
        origData.current = {
            orig: new Float32Array(geo.attributes.position.array),
            norms: new Float32Array(geo.attributes.normal.array),
        };
    }, []);
    // ── Sync prop changes → material / uniforms ─────────────────────────────
    useEffect(() => {
        if (meshRef.current) {
            const mat = meshRef.current.material;
            mat.color.set(meshColor);
            mat.roughness = roughness;
            mat.metalness = metalness;
        }
        if (atmosphereRef.current) {
            atmosphereRef.current.uniforms.u_color1.value.copy(colorObjs.c1);
            atmosphereRef.current.uniforms.u_color2.value.copy(colorObjs.c2);
            atmosphereRef.current.uniforms.u_color3.value.copy(colorObjs.c3);
            atmosphereRef.current.uniforms.u_intensity.value = glowIntensity * 0.65;
        }
    }, [colorObjs, meshColor, roughness, metalness, glowIntensity]);
    // ── Animation loop ──────────────────────────────────────────────────────
    useFrame(({ clock }, delta) => {
        // Tick state interpolation
        stateTick(delta);
        const sv = stateRef.current;
        const t = clock.getElapsedTime();
        const spd = sv.speed;
        const na = sv.noiseAmplitude;
        const ns = propsRef.current.noiseScale;
        // Sync interpolated glowIntensity into atmosphere uniform
        if (atmosphereRef.current) {
            atmosphereRef.current.uniforms.u_intensity.value = sv.glowIntensity * 0.65;
        }
        // Vertex deformation
        if (meshRef.current && origData.current) {
            const geo = meshRef.current.geometry;
            const pos = geo.attributes.position.array;
            const { orig, norms } = origData.current;
            const count = geo.attributes.position.count;
            for (let i = 0; i < count; i++) {
                const i3 = i * 3;
                const ox = orig[i3], oy = orig[i3 + 1], oz = orig[i3 + 2];
                const nx = norms[i3], ny = norms[i3 + 1], nz = norms[i3 + 2];
                const n = simplex3(ox * ns + t * 0.15 * spd, oy * ns + t * 0.12 * spd, oz * ns + t * 0.1 * spd);
                pos[i3] = ox + nx * n * na;
                pos[i3 + 1] = oy + ny * n * na;
                pos[i3 + 2] = oz + nz * n * na;
            }
            geo.attributes.position.needsUpdate = true;
            geo.computeVertexNormals();
            meshRef.current.rotation.y = t * 0.03 * spd;
        }
        // Breathing — gentle scale on the whole group
        if (groupRef.current) {
            const breath = Math.sin(t * 0.6 * spd);
            const s = 1 + 0.025 * breath;
            groupRef.current.scale.set(s, s, s);
        }
        // Update atmosphere time uniform
        if (atmosphereRef.current) {
            atmosphereRef.current.uniforms.u_time.value = t * spd;
        }
    });
    return (jsxs("group", { ref: groupRef, children: [jsx(Environment, { preset: "sunset" }), jsx("ambientLight", { intensity: 2 }), jsx("pointLight", { color: colors[0], intensity: 18, distance: 50, position: [-3, 1, 2] }), jsx("pointLight", { color: colors[1], intensity: 18, distance: 50, position: [3, -1, 2] }), jsx("pointLight", { color: colors[2], intensity: 10, distance: 50, position: [0, 0, 4] }), jsx("pointLight", { color: "#6428b4", intensity: 12, distance: 50, position: [0, -3, 2] }), jsxs("mesh", { ref: meshRef, children: [jsx("sphereGeometry", { args: [1, 64, 64] }), jsx("meshStandardMaterial", { color: meshColor, roughness: roughness, metalness: metalness, envMapIntensity: 2.5, emissive: "#5A1878", emissiveIntensity: 0.8 })] }), jsxs("mesh", { scale: glowSize, children: [jsx("sphereGeometry", { args: [1, 32, 32] }), jsx("shaderMaterial", { ref: atmosphereRef, vertexShader: glowVertex, fragmentShader: atmosphereFragment, uniforms: atmosphereUniforms, transparent: true, side: BackSide, blending: CustomBlending, blendEquation: AddEquation, blendSrc: OneFactor, blendDst: OneFactor, blendSrcAlpha: ZeroFactor, blendDstAlpha: OneFactor, depthWrite: false })] })] }));
};
// ── Public Liquid variant ────────────────────────────────────────────────────
const DEFAULT_COLORS = ["#2C35B7", "#C9242F", "#9DD9EB"];
const Liquid = ({ colors = DEFAULT_COLORS, meshColor = "#350F3F", speed = 1.0, roughness = 0.15, metalness = 0.95, noiseScale = 0.8, noiseAmplitude = 0.1, glowIntensity = 1.0, glowSize = 1.8, state, }) => {
    return (jsxs(Fragment, { children: [jsx(Canvas, { className: "!absolute inset-0 w-full h-full", style: {
                    filter: [
                        'drop-shadow(0 0 10px rgba(192, 132, 252, 0.7))',
                        'drop-shadow(0 0 25px rgba(147, 51, 234, 0.35))',
                        'drop-shadow(0 0 50px rgba(124, 58, 237, 0.15))',
                    ].join(' '),
                }, dpr: [1, 2], camera: { position: [0, 0, 3.2], fov: 50 }, gl: { antialias: true, alpha: true, premultipliedAlpha: false, toneMapping: ACESFilmicToneMapping }, onCreated: ({ gl }) => {
                    gl.toneMappingExposure = 1.8;
                    gl.setClearColor(0x000000, 0);
                }, children: jsx(LiquidScene, { colors: colors, meshColor: meshColor, speed: speed, roughness: roughness, metalness: metalness, noiseScale: noiseScale, noiseAmplitude: noiseAmplitude, glowIntensity: glowIntensity, glowSize: glowSize, state: state }) }), jsx("div", { className: "absolute inset-0 pointer-events-none", style: {
                    background: "radial-gradient(circle at center, rgba(255,255,255,0.35) 0%, rgba(180,120,255,0.2) 15%, rgba(100,40,180,0.08) 35%, transparent 55%)",
                    mixBlendMode: "screen",
                } })] }));
};

export { Liquid };
