import { VisualizerInterface } from './VisualizerInterface.js';

const fragmentShader = `
uniform float u_time;
uniform float u_beat;
uniform float u_opacity;
uniform vec2 u_resolution;
uniform vec3 u_colors[16];
uniform int u_colorCount;
uniform float u_seed;
varying vec2 vUv;

vec3 hsv2rgb(vec3 c) {
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}

void main() {
    float ledCountX = u_resolution.x;
    float ledCountY = u_resolution.y;
    
    vec2 gridUV = vec2(vUv.x * ledCountX, vUv.y * ledCountY);
    
    vec2 gridDeriv = fwidth(gridUV);
    float gridDensity = max(gridDeriv.x, gridDeriv.y);
    float blurFactor = smoothstep(0.3, 0.8, gridDensity);

    vec2 cell = fract(gridUV);
    vec2 uv = mix((floor(gridUV) + 0.5) / vec2(ledCountX, ledCountY), vUv, blurFactor);
    
    float dist = distance(cell, vec2(0.5));
    float edgeSoftness = clamp(gridDensity * 1.5, 0.0, 0.5);
    float mask = 1.0 - smoothstep(0.35 - edgeSoftness, 0.45 + edgeSoftness, dist);
    mask = mix(mask, 1.0, blurFactor);
    
    float d = length(uv - 0.5);
    float angle = atan(uv.y - 0.5, uv.x - 0.5);
    
    float wave = sin(d * 20.0 - u_time * 2.0 + u_seed);
    float beatWave = sin(angle * 5.0 + u_time + u_seed * 0.1) * u_beat;
    
    float hue = fract(u_time * 0.1 + d * 0.2 + u_seed * 0.01);
    float val = 0.5 + 0.5 * sin(wave + beatWave);
    
    vec3 finalColor;
    if (u_colorCount > 0) {
        float indexFloat = hue * float(u_colorCount);
        int index = int(mod(indexFloat, float(u_colorCount)));
        vec3 c = vec3(0.0);
        for (int i = 0; i < 16; i++) {
            if (i == index) {
                c = u_colors[i];
                break;
            }
        }
        finalColor = c * val;
    } else {
        finalColor = hsv2rgb(vec3(hue, 0.8, val));
    }
    
    gl_FragColor = vec4(finalColor, mask * u_opacity);
}
`;

export class ClassicVisualizer extends VisualizerInterface {
    getName() {
        return "Classic Wave";
    }

    getFragmentShader() {
        return fragmentShader;
    }
}
