#ifndef VOXEL_LIGHT_PROPAGATION_GLSL
#define VOXEL_LIGHT_PROPAGATION_GLSL

// LightPropagation.glsl - Voxel Light Propagation (Flood Fill)
// Multi-bounce light propagation using iterative flood fill
// Based on 0fps.net/2018/02/21/voxel-lighting/

#include "VoxelStructure.glsl"

//============================================================================//
// PROPAGATION SETTINGS
//============================================================================//

#ifndef VXGI_PROPAGATION_STEPS
#define VXGI_PROPAGATION_STEPS 6 // [4 6 8 10 12]
#endif

#ifndef VXGI_PROPAGATION_DAMPING
#define VXGI_PROPAGATION_DAMPING 0.85 // [0.7 0.8 0.85 0.9 0.95]
#endif

#ifndef VXGI_DISTANCE_ATTENUATION
#define VXGI_DISTANCE_ATTENUATION 0.1 // [0.05 0.1 0.15 0.2]
#endif

#ifndef VXGI_MIN_LIGHT_THRESHOLD
#define VXGI_MIN_LIGHT_THRESHOLD 0.001
#endif

//============================================================================//
// LIGHT PROPAGATION ALGORITHM
//============================================================================//

// Propagate light from one voxel to its neighbors
vec3 PropagateToNeighbor(
    vec3 sourceLight,
    vec3 sourceAlbedo,
    vec3 neighborAlbedo,
    float distance,
    float opacity
) {
    // Light attenuates with distance
    float attenuation = exp(-distance * VXGI_DISTANCE_ATTENUATION);
    
    // Light is absorbed and re-emitted by albedo (diffuse reflection)
    vec3 propagatedLight = sourceLight * neighborAlbedo * attenuation * VXGI_PROPAGATION_DAMPING;
    
    // Reduce by opacity (solid voxels block more light)
    propagatedLight *= (1.0 - opacity * 0.5);
    
    return propagatedLight;
}

//============================================================================//
// SINGLE PROPAGATION STEP
//============================================================================//

// Perform one iteration of flood fill propagation


//============================================================================//
// MULTI-STEP PROPAGATION
//============================================================================//

// Perform multiple propagation steps with ping-pong buffers
void PropagateLight(
    ivec3 voxel,
    sampler3D voxelAlbedoTex,
    sampler3D voxelGITexRead,
    layout(rgba16f) image3D voxelGIImageWrite
) {
    vec3 propagatedLight = PropagationStep(voxel, voxelAlbedoTex, voxelGITexRead);
    
    // Write result
    imageStore(voxelGIImageWrite, voxel, vec4(propagatedLight, 1.0));
}

//============================================================================//
// OPTIMIZED PROPAGATION (CHECKERBOARD)
//============================================================================//

#ifdef VXGI_CHECKERBOARD_PROPAGATION

// Checkerboard pattern for faster propagation
bool IsCheckerboardActive(ivec3 voxel, int frame) {
    int sum = voxel.x + voxel.y + voxel.z + frame;
    return (sum % 2) == 0;
}

// Propagate only active checkerboard voxels
void PropagateCheckerboard(
    ivec3 voxel,
    int frameCounter,
    sampler3D voxelAlbedoTex,
    sampler3D voxelGITexRead,
    layout(rgba16f) image3D voxelGIImageWrite
) {
    if (!IsCheckerboardActive(voxel, frameCounter)) return;
    
    PropagateLight(voxel, voxelAlbedoTex, voxelGITexRead, voxelGIImageWrite);
}

#endif

//============================================================================//
// DIRECTIONAL PROPAGATION
//============================================================================//

// Propagate with directional bias (sunlight direction)
vec3 PropagationStepDirectional(
    ivec3 voxel,
    vec3 sunDir,
    sampler3D voxelAlbedoTex,
    sampler3D voxelGITexRead
) {
    if (!IsVoxelInBounds(voxel)) return vec3(0.0);
    
    vec3 texCoord = VoxelToTexCoord(voxel);
    vec4 voxelAlbedo = texture(voxelAlbedoTex, texCoord);
    
    if (voxelAlbedo.a < 0.01) return vec3(0.0);
    
    vec4 currentLight = texture(voxelGITexRead, texCoord);
    vec3 accumulatedLight = currentLight.rgb;
    float totalWeight = 1.0;
    
    // Sample neighbors with directional weighting

    
    return accumulatedLight / totalWeight;
}

//============================================================================//
// BATCH PROCESSING
//============================================================================//

// Process batch of voxels for compute shader
void PropagateLightBatch(
    ivec3 baseVoxel,
    ivec3 batchSize,
    sampler3D voxelAlbedoTex,
    sampler3D voxelGITexRead,
    layout(rgba16f) image3D voxelGIImageWrite
) {
    for (int x = 0; x < batchSize.x; x++) {
        for (int y = 0; y < batchSize.y; y++) {
            for (int z = 0; z < batchSize.z; z++) {
                ivec3 voxel = baseVoxel + ivec3(x, y, z);
                PropagateLight(voxel, voxelAlbedoTex, voxelGITexRead, voxelGIImageWrite);
            }
        }
    }
}

//============================================================================//
// TEMPORAL SMOOTHING
//============================================================================//

// Blend with previous frame for temporal stability
vec3 TemporalBlend(vec3 currentLight, vec3 previousLight, float blendFactor) {
    return mix(currentLight, previousLight, blendFactor);
}

// Apply temporal filter to reduce flickering
vec3 ApplyTemporalFilter(
    ivec3 voxel,
    vec3 currentLight,
    sampler3D previousGITex,
    float temporalBlend
) {
    vec3 texCoord = VoxelToTexCoord(voxel);
    vec3 previousLight = texture(previousGITex, texCoord).rgb;
    
    return TemporalBlend(currentLight, previousLight, temporalBlend);
}

//============================================================================//
// FULL PROPAGATION PIPELINE
//============================================================================//

// Complete propagation with all features
void FullPropagation(
    ivec3 voxel,
    vec3 sunDir,
    bool useDirectional,
    bool useTemporal,
    sampler3D voxelAlbedoTex,
    sampler3D voxelGITexRead,
    sampler3D previousGITex,
    layout(rgba16f) image3D voxelGIImageWrite,
    float temporalBlend
) {
    // Choose propagation method
    vec3 propagatedLight;
    if (useDirectional) {
        propagatedLight = PropagationStepDirectional(voxel, sunDir, voxelAlbedoTex, voxelGITexRead);
    } else {
        propagatedLight = PropagationStep(voxel, voxelAlbedoTex, voxelGITexRead);
    }
    
    // Apply temporal filter if enabled
    if (useTemporal) {
        propagatedLight = ApplyTemporalFilter(voxel, propagatedLight, previousGITex, temporalBlend);
    }
    
    // Write result
    imageStore(voxelGIImageWrite, voxel, vec4(propagatedLight, 1.0));
}

#endif // VOXEL_LIGHT_PROPAGATION_GLSL
