use crate::prelude::*;

/// Grid coordinates to world coordinates
pub fn grid_position_to_translation(grid_pos: IVec2, grid_dimensions: &WorldDimensions) -> Vec3 {
    Vec3::new(
        (grid_pos.x * grid_dimensions.cell_width + grid_dimensions.cell_width / 2) as f32,
        (grid_pos.y * grid_dimensions.cell_width + grid_dimensions.cell_width / 2) as f32,
        2.,
    )
}

/// World coordinates to grid coordinates
pub fn translation_to_grid_pos(
    translation: Vec3,
    world_dimensions: &WorldDimensions,
) -> Option<IVec2> {
    let x = (translation.x as i32) / world_dimensions.cell_width;
    let y = (translation.y as i32) / world_dimensions.cell_width;

    match is_in_bounds(&IVec2::new(x, y), &world_dimensions) {
        true => Some(IVec2::new(x, y)),
        false => None,
    }
}

/// Snaps arbitrary coordinates to align with the in-game grid
pub fn snap_to_grid(translation: Vec3, world_dimensions: &WorldDimensions) -> Option<Vec3> {
    let maybe_grid_position = translation_to_grid_pos(translation, &world_dimensions);
    maybe_grid_position
        .map(|grid_position| grid_position_to_translation(grid_position, &world_dimensions))
}

pub fn grid_pos_to_idx(tile_coords: &IVec2, grid_dimensions: &WorldDimensions) -> Option<usize> {
    if !is_in_bounds(tile_coords, &grid_dimensions) {
        return None;
    }

    let w = grid_dimensions.cols;

    Some((tile_coords.y * w + tile_coords.x) as usize)
}

/// Check if the tile in inside the bounds of the world
/// returns true for [0, WORLD_SIZE)
pub fn is_in_bounds(tile_coords: &IVec2, world_dimensions: &WorldDimensions) -> bool {
    let x = tile_coords.x;
    let y = tile_coords.y;

    x >= 0 && y >= 0 && x < world_dimensions.cols && y < world_dimensions.rows
}
