use glam::{Mat4, Vec3};

use crate::render::billboard::{BillboardDrawCall, BillboardVertex, BubbleUniforms};
use crate::world::World;

const BUBBLE_WIDTH: f32 = 2.2;
const BUBBLE_HEIGHT: f32 = 1.1;
const BODY_FRAC: f32 = 0.78;
const CORNER_R: f32 = 0.18;
const BORDER_W: f32 = 0.06;
const HEIGHT_OFFSET: f32 = 8.2;

const FILL_COLOR: [f32; 4] = [0.05, 0.05, 0.05, 1.0];
const BORDER_COLOR: [f32; 4] = [1.0, 1.0, 1.0, 1.0];

pub fn dialog_bubble_render_system(
    world: &World,
    camera_pos: Vec3,
    view_proj: Mat4,
) -> Vec<BillboardDrawCall>
{
    let mut calls = Vec::new();

    for bubble_entity in world.bubble_tags.all()
    {
        let character_entity = match world
            .dialog_bubbles
            .with(bubble_entity, |b| b.character_entity)
        {
            Some(e) => e,
            None => continue,
        };

        let character_pos = match world.transforms.with(character_entity, |t| t.position)
        {
            Some(p) => p,
            None => continue,
        };

        let body_half_h = BUBBLE_HEIGHT * BODY_FRAC * 0.5;
        let tail_height = BUBBLE_HEIGHT * (1.0 - BODY_FRAC);
        let anchor = character_pos + Vec3::Y * (HEIGHT_OFFSET + body_half_h);

        let to_camera = camera_pos - anchor;
        let forward = if to_camera.length_squared() > 1e-6
        {
            to_camera.normalize()
        }
        else
        {
            Vec3::Z
        };

        let up_ref = Vec3::Y;
        let right = if forward.abs().dot(up_ref) > 0.99
        {
            Vec3::X
        }
        else
        {
            up_ref.cross(forward).normalize()
        };
        let up = forward.cross(right).normalize();

        let half_w = BUBBLE_WIDTH * 0.5;
        let total_down = body_half_h + tail_height;

        // Corners: tl → tr → br → bl (CCW in clip space when billboard faces camera).
        let tl = anchor - right * half_w + up * body_half_h;
        let tr = anchor + right * half_w + up * body_half_h;
        let br = anchor + right * half_w - up * total_down;
        let bl = anchor - right * half_w - up * total_down;

        let vertices = [
            BillboardVertex {
                position: tl.to_array(),
                uv: [0.0, 0.0],
            },
            BillboardVertex {
                position: tr.to_array(),
                uv: [1.0, 0.0],
            },
            BillboardVertex {
                position: br.to_array(),
                uv: [1.0, 1.0],
            },
            BillboardVertex {
                position: bl.to_array(),
                uv: [0.0, 1.0],
            },
        ];

        let uniforms = BubbleUniforms {
            view_proj: view_proj.to_cols_array_2d(),
            size: [BUBBLE_WIDTH, BUBBLE_HEIGHT],
            body_frac: BODY_FRAC,
            corner_r: CORNER_R,
            border_w: BORDER_W,
            _pad1: [0.0; 3],
            fill_color: FILL_COLOR,
            border_color: BORDER_COLOR,
            _pad2: [0.0; 32],
        };

        calls.push(BillboardDrawCall { vertices, uniforms });
    }

    calls
}
