use crate::components::DissolveComponent;
use crate::world::World;

pub fn tree_dissolve_update_system(world: &mut World, delta: f32)
{
    for entity in world.dissolves.all()
    {
        if let Some(dissolve) = world.dissolves.get_mut(entity)
        {
            let diff = dissolve.target_amount - dissolve.amount;
            dissolve.amount += diff * dissolve.transition_speed * delta;
            dissolve.amount = dissolve.amount.clamp(0.0, 1.0);
        }
    }
}

pub fn tree_occlusion_system(world: &mut World)
{
    let player_entity = world.player_tags.all().first().copied();
    let player_pos = player_entity.and_then(|e| world.transforms.get(e).map(|t| t.position));

    if let Some(player_pos) = player_pos
    {
        let camera_entity = world.active_camera().map(|(e, _)| e);
        let camera_pos = camera_entity.and_then(|e| world.transforms.get(e).map(|t| t.position));

        if let Some(camera_pos) = camera_pos
        {
            let to_player = player_pos - camera_pos;
            let distance_to_player = to_player.length();

            if distance_to_player < 0.01
            {
                return;
            }

            let to_player_normalized = to_player.normalize();

            for tree_entity in world.tree_tags.all()
            {
                if let Some(tree_transform) = world.transforms.get(tree_entity)
                {
                    let tree_pos = tree_transform.position;
                    let to_tree = tree_pos - camera_pos;
                    let distance_to_tree = to_tree.length();

                    if distance_to_tree < distance_to_player
                    {
                        let projection = to_tree.dot(to_player_normalized);

                        if projection > 0.0
                        {
                            let perpendicular_vec = to_tree - to_player_normalized * projection;
                            let perp_distance = perpendicular_vec.length();

                            let occlusion_radius = 2.5;

                            if perp_distance < occlusion_radius
                            {
                                let dissolve_amount =
                                    1.0 - (perp_distance / occlusion_radius).clamp(0.0, 1.0);

                                if let Some(dissolve) = world.dissolves.get_mut(tree_entity)
                                {
                                    dissolve.target_amount = dissolve_amount;
                                }
                                else
                                {
                                    let mut dissolve = DissolveComponent::new();
                                    dissolve.target_amount = dissolve_amount;
                                    world.dissolves.insert(tree_entity, dissolve);
                                }
                                continue;
                            }
                        }
                    }

                    if let Some(dissolve) = world.dissolves.get_mut(tree_entity)
                    {
                        dissolve.target_amount = 0.0;
                    }
                }
            }
        }
    }
}
