// ============================================================================
// FOLIAGE ANIMATION
// ============================================================================
#ifndef FOLIAGES_GLSL
#define FOLIAGES_GLSL

#include "/lib/weather.glsl"
#include "/lib/noises.glsl"

const float golden_angle = 2.39996322973;

const int BLOCK_SMALL_PLANTS      = 2;
const int BLOCK_TALL_PLANTS_LOWER = 3;
const int BLOCK_TALL_PLANTS_UPPER = 4;
const int BLOCK_LEAVES            = 5;
const int BLOCK_VINES             = 8;

float sqr(float x) { return x * x; }

// ============================================================================
// LEAVES NOISES
// ============================================================================
float get_leaves_noise_val(vec3 p) {
    float angleRad = radians(float(WIND_BASE_ANGLE));
    vec2 wind_dir = vec2(sin(angleRad), cos(angleRad));
    vec2 uv = p.xy * 0.02; 
    uv -= wind_dir * p.z * 0.5;
    
    float noise_val = 0.0;
    #if LEAVES_NOISE_TYPE == 1
        noise_val = texture2DLod(noisetex1, uv, 0.0).r;
    #elif LEAVES_NOISE_TYPE == 2
        noise_val = texture2DLod(noisetex2, uv, 0.0).r;
    #elif LEAVES_NOISE_TYPE == 3
        noise_val = texture2DLod(noisetex3, uv, 0.0).r;
    #elif LEAVES_NOISE_TYPE == 4
        noise_val = texture2DLod(noisetex4, uv, 0.0).r;
    #elif LEAVES_NOISE_TYPE == 5
        noise_val = texture2DLod(noisetex5, uv, 0.0).r;
    #elif LEAVES_NOISE_TYPE == 6
        noise_val = texture2DLod(noisetex6, uv, 0.0).r;
    #endif
    
    return pow(clamp(noise_val, 0.0, 1.0), float(LEAVES_NOISE_SMOOTHNESS));
}

// ============================================================================
// FOLIAGES NOISES
// ============================================================================
float get_foliage_noise_val(vec3 world_pos, vec2 wind_dir, float t, float scale) {
    vec2 uv = world_pos.xz * 0.01 * scale;
    uv -= wind_dir * t * 0.5;
    
    float noise_val = 0.0;
    #if FOLIAGE_NOISE_TYPE == 1
        noise_val = texture2DLod(noisetex1, uv, 0.0).r;
    #elif FOLIAGE_NOISE_TYPE == 2
        noise_val = texture2DLod(noisetex2, uv, 0.0).r;
    #elif FOLIAGE_NOISE_TYPE == 3
        noise_val = texture2DLod(noisetex3, uv, 0.0).r;
    #elif FOLIAGE_NOISE_TYPE == 4
        noise_val = texture2DLod(noisetex4, uv, 0.0).r;
    #elif FOLIAGE_NOISE_TYPE == 5
        noise_val = texture2DLod(noisetex5, uv, 0.0).r;
    #elif FOLIAGE_NOISE_TYPE == 6
        noise_val = texture2DLod(noisetex6, uv, 0.0).r;
    #endif

    return pow(clamp(noise_val, 0.0, 1.0), float(FOLIAGE_NOISE_SMOOTHNESS));
}

// Apply rustling deformation to leaves.
vec3 get_leaf_deformation(vec3 world_pos, float wind_speed, float wind_strength) {
    // Calculate constant time step for smooth animation.
    float t = frameTimeCounter * wind_speed * float(LEAVES_WIND_SPEED_MULTIPLIER) * float(WIND_GLOBAL_SPEED) * 4.0;

    vec3 scaled_pos = world_pos * float(LEAVES_NOISE_SCALE);
    float nx = get_leaves_noise_val(vec3(scaled_pos.y, scaled_pos.z, t));
    float ny = get_leaves_noise_val(vec3(scaled_pos.x, scaled_pos.z, t + 10.0));
    float nz = get_leaves_noise_val(vec3(scaled_pos.x, scaled_pos.y, t + 20.0));

    vec3 wave = vec3(nx, ny, nz) * 2.0 - 1.0;
    
    // Scale wave amplitude by wind strength.
    vec3 mult = vec3(0.15, 0.08, 0.15) * wind_strength * float(LEAVES_WIND_INTENSITY);
    return wave * mult;
}

// Apply bending displacement to grass and plants.
vec3 get_grass_displacement(vec3 world_pos, float wind_speed, float wind_strength) {
    vec2 weather_wind = getWindVector(float(CLOUD_RAIN_SPEED_MULTIPLIER), float(FOLIAGE_WIND_VARIATION_INTENSITY));
    vec2 wind_dir = normalize(weather_wind + vec2(0.001));
    
    float gust_intensity = mix(0.5, 1.5, length(weather_wind) / float(WIND_GLOBAL_SPEED));
    float constant_t = frameTimeCounter * wind_speed * float(FOLIAGE_WIND_SPEED_MULTIPLIER) * float(WIND_GLOBAL_SPEED);
    float angleRad = radians(float(WIND_BASE_ANGLE));
    vec2 wind_dir_uv = vec2(sin(angleRad), cos(angleRad));
    float raw_noise = get_foliage_noise_val(world_pos, wind_dir_uv, constant_t, float(FOLIAGE_NOISE_SCALE));

    float gust_amount = smoothstep(0.05, 0.95, raw_noise) * gust_intensity;
    float base_force = 0.5;
    float raw_gust = gust_amount * wind_strength * float(FOLIAGE_WIND_INTENSITY) * base_force;
    float max_bend = max(float(FOLIAGE_BEND_STRENGTH), 0.001);
    
    float final_gust = (raw_gust * max_bend) / (max_bend + raw_gust);
    
    vec2 horizontal_disp = wind_dir * final_gust;
    float vertical_dip = max(-length(horizontal_disp) * 0.4, -0.3);
    
    // Smooth the spatial frequency (from 32.0 to 2.0) and slow down the wave.
    vec3 wp = 2.0 * world_pos + (constant_t * 1.5) + vec3(0.0, golden_angle, 2.0 * golden_angle);
    
    // Remove harsh high-frequency harmonics (sin 4.0*wp) for a gentle, broad sway.
    vec3 wobble = (sin(wp) + 0.3 * sin(1.5 * wp)) * 0.04 * wind_strength;

    return vec3(horizontal_disp.x, vertical_dip, horizontal_disp.y) + wobble;
}

// Apply displacement when the player walks through foliage.
vec3 get_player_displacement(vec3 world_pos) {
    vec2 to_player_xz = eyePosition.xz - world_pos.xz;
    float dist = length(to_player_xz);
    float radius = max(float(PLAYER_INTERACTION_RADIUS), 0.001);
    
    if (dist >= radius) return vec3(0.0);

    vec2 push_dir = (dist > 0.001) ? (to_player_xz / dist) : vec2(0.0);
    
    float falloff = 1.0 - smoothstep(0.0, radius, dist);
    float raw_force = falloff * falloff * float(PLAYER_INTERACTION_INTENSITY);

    float max_push = 0.6; // La plante ne s'éloignera jamais de plus de 0.6 bloc
    float force = (raw_force * max_push) / (max_push + raw_force);

    float vertical_dip = -force * 0.7;

    return vec3(-push_dir.x * force, vertical_dip, -push_dir.y * force);
}

// Main function to calculate final vertex animation.
vec3 animate_vertex(vec3 world_pos, bool is_top_vertex, float skylight, int block_id, bool is_fluff) {
    float wind_speed = 0.8;
    float effectiveSkylight = max(skylight, 0.5); 
    
    // Separate wind strengths with their respective rain multipliers.
    float leaf_wind_strength = sqr(effectiveSkylight) * (0.25 + 0.66 * rainStrength * float(LEAVES_RAIN_INTENSITY_MULTI));
    float foliage_wind_strength = sqr(effectiveSkylight) * (0.25 + 0.66 * rainStrength * float(FOLIAGES_RAIN_INTENSITY_MULTI));

    vec3 player_disp = vec3(0.0);
    #if PLAYER_INTERACTION == 1
        // Prevent interaction displacement on both leaves and vines.
        if (abs(eyePosition.y - world_pos.y) < 4.0 && block_id != BLOCK_LEAVES && block_id != BLOCK_VINES) {
            // L'intensité est maintenant calculée et sécurisée à l'intérieur de la fonction
            player_disp = get_player_displacement(world_pos);
        }
    #endif

    // Animate leaves independently.
    if (block_id == BLOCK_LEAVES) {
        return world_pos + get_leaf_deformation(world_pos, wind_speed, leaf_wind_strength);
    }
    
    // Animate vines using leaf noise but with divided intensity.
    if (block_id == BLOCK_VINES) {
        return world_pos + get_leaf_deformation(world_pos, wind_speed, leaf_wind_strength / float(VINES_WIND_INTENSITY_DIVISOR));
    }

    // Grass and other plants use the foliage wind strength.
    vec3 base_disp = get_grass_displacement(world_pos, wind_speed, foliage_wind_strength) + player_disp;
    
    // Animate 3D grass fluff while keeping roots static.
    if (is_fluff) {
        return world_pos + base_disp * float(is_top_vertex) * float(GRASS_3D_WIND);
    }

    if (block_id == BLOCK_SMALL_PLANTS) {
        return world_pos + base_disp * float(is_top_vertex);
    }
    
    if (block_id == BLOCK_TALL_PLANTS_LOWER) {
        return world_pos + (base_disp * 0.5) * float(is_top_vertex);
    }
    
    if (block_id == BLOCK_TALL_PLANTS_UPPER) {
        return world_pos + base_disp * (0.5 + 0.5 * float(is_top_vertex));
    }

    return world_pos;
}

#endif