use glam::Vec3Swizzles;

use crate::prelude::*;

use super::math::round_to_even;

/// Draw sprite
///
/// # Arguments
///
/// * `g` - Engine
/// * `sprite` - Sprite
/// * `src` - Source rect from left top to right bottom
/// * `target` - Target rect from left top to right bottom
/// * `z` - Z index
fn draw(g: &mut Engine, sprite: &mut Sprite, src: Option<Rect>, target: Rect, z: f32) {
    sprite.src = src;
    let size = target.max - target.min;
    let pos = (target.min + size * 0.5).extend(z);
    // Set the sprite's output size directly; Transform carries only pos/scale/rotation
    sprite.size = size.as_uvec2();
    let transform = Transform::new(pos);
    g.draw(sprite, transform);
}

/// Draw nine slice
///
/// # Arguments
///
/// * `g` - Engine
/// * `image` - Sprite
/// * `slice` - Rect, nine slice area
/// * `tf` - Transform
///
pub fn draw_nine_slice(
    g: &mut Engine,
    image: &Sprite,
    Rect { min, max }: Rect,
    tf: Transform,
    size: Vec2,
) {
    let z_index = tf.pos.z;
    // if pos or size is odd, the nine slice will be offset by 1 pixel, so we need to round to even
    let pos = round_to_even(tf.pos.xy());
    let size = round_to_even(size);
    let mut image = image.clone();
    // texture size
    let texture_size = image.size().as_vec2();
    let tex_w = texture_size.x;
    let tex_h = texture_size.y;

    // get fixed parts
    let left = min.x;
    let bottom = min.y;
    let right = tex_w - max.x;
    let top = tex_h - max.y;

    // get center src
    let center_src_w = max.x - min.x;
    let center_src_h = max.y - min.y;

    // bottom left
    let bottom_left = Vec2 {
        x: pos.x - size.x / 2.0,
        y: pos.y - size.y / 2.0,
    };

    // center dst (strength)
    let center_dst_w = size.x - (left + right);
    let center_dst_h = size.y - (top + bottom);

    // bottom left
    let src_bl = Rect {
        min: Vec2::new(0.0, max.y),
        max: Vec2::new(left, max.y + top),
    };
    let dst_bl = Rect {
        min: bottom_left,
        max: bottom_left + Vec2::new(left, bottom),
    };
    draw(g, &mut image, Some(src_bl), dst_bl, z_index);

    // bottom
    let src_bottom = Rect {
        min: Vec2::new(left, max.y),
        max: Vec2::new(left + center_src_w, max.y + top),
    };
    let dst_bottom = Rect {
        min: Vec2::new(bottom_left.x + left, bottom_left.y),
        max: Vec2::new(bottom_left.x + left + center_dst_w, bottom_left.y + bottom),
    };
    draw(g, &mut image, Some(src_bottom), dst_bottom, z_index);

    // bottom right
    let src_br = Rect {
        min: max,
        max: max + Vec2::new(right, top),
    };
    let dst_br = Rect {
        min: Vec2::new(bottom_left.x + left + center_dst_w, bottom_left.y),
        max: Vec2::new(
            bottom_left.x + left + center_dst_w + right,
            bottom_left.y + bottom,
        ),
    };
    draw(g, &mut image, Some(src_br), dst_br, z_index);

    // left
    let src_left = Rect {
        min: Vec2::new(0.0, bottom),
        max: Vec2::new(left, bottom + center_src_h),
    };
    let dst_left = Rect {
        min: Vec2::new(bottom_left.x, bottom_left.y + bottom),
        max: Vec2::new(bottom_left.x + left, bottom_left.y + bottom + center_dst_h),
    };
    draw(g, &mut image, Some(src_left), dst_left, z_index);

    // center
    let src_center = Rect {
        min: Vec2::new(left, bottom),
        max: Vec2::new(left + center_src_w, bottom + center_src_h),
    };
    let dst_center = Rect {
        min: Vec2::new(bottom_left.x + left, bottom_left.y + bottom),
        max: Vec2::new(
            bottom_left.x + left + center_dst_w,
            bottom_left.y + bottom + center_dst_h,
        ),
    };
    draw(g, &mut image, Some(src_center), dst_center, z_index);

    // right
    let src_right = Rect {
        min: Vec2::new(max.x, bottom),
        max: Vec2::new(max.x + right, bottom + center_src_h),
    };
    let dst_right = Rect {
        min: Vec2::new(bottom_left.x + left + center_dst_w, bottom_left.y + bottom),
        max: Vec2::new(
            bottom_left.x + left + center_dst_w + right,
            bottom_left.y + bottom + center_dst_h,
        ),
    };
    draw(g, &mut image, Some(src_right), dst_right, z_index);

    // top left
    let src_tl = Rect {
        min: Vec2::new(0.0, 0.0),
        max: Vec2::new(left, bottom),
    };
    let dst_tl = Rect {
        min: Vec2::new(bottom_left.x, bottom_left.y + bottom + center_dst_h),
        max: Vec2::new(
            bottom_left.x + left,
            bottom_left.y + bottom + center_dst_h + top,
        ),
    };
    draw(g, &mut image, Some(src_tl), dst_tl, z_index);

    // top
    let src_top = Rect {
        min: Vec2::new(left, 0.0),
        max: Vec2::new(left + center_src_w, bottom),
    };
    let dst_top = Rect {
        min: Vec2::new(bottom_left.x + left, bottom_left.y + bottom + center_dst_h),
        max: Vec2::new(
            bottom_left.x + left + center_dst_w,
            bottom_left.y + bottom + center_dst_h + top,
        ),
    };
    draw(g, &mut image, Some(src_top), dst_top, z_index);

    // top right
    let src_tr = Rect {
        min: Vec2::new(max.x, 0.0),
        max: Vec2::new(max.x + right, bottom),
    };
    let dst_tr = Rect {
        min: Vec2::new(
            bottom_left.x + left + center_dst_w,
            bottom_left.y + bottom + center_dst_h,
        ),
        max: Vec2::new(
            bottom_left.x + left + center_dst_w + right,
            bottom_left.y + bottom + center_dst_h + top,
        ),
    };
    draw(g, &mut image, Some(src_tr), dst_tr, z_index);
}
