use std::sync::Arc;
use std::time::{Duration, Instant};

use cgmath::{Deg, Euler};
use rapier3d::dynamics::{RigidBody, RigidBodyHandle};
use rapier3d::geometry::Collider as r3dCollider;
use rapier3d::geometry::ColliderHandle;
use wgpu::{BindGroup, Buffer, TextureView};

use crate::runtime::state::{TomlPositionDescription, TomlRotationDescription};
use imgui::Ui;

// a component is any type that is 'static, sized, send and sync

pub struct ImguiWindow<'a, T> {
    pub window: fn() -> imgui::Window<'a>,
    pub func: fn(&Ui, Vec<&T>),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct LoopState {
    pub delta_time: Duration,
    pub start_time: Instant,
    pub step_size: f32,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Position {
    pub x: f32,
    pub y: f32,
    pub z: f32,
    pub rot: cgmath::Euler<Deg<f32>>,
}

impl Default for Position {
    fn default() -> Self {
        Position {
            x: 0.0,
            y: 0.0,
            z: 0.0,
            rot: Euler {
                x: Deg(0.0),
                y: Deg(0.0),
                z: Deg(0.0),
            },
        }
    }
}

impl From<TomlPositionDescription> for Position {
    fn from(pos: TomlPositionDescription) -> Self {
        let euler = match pos.rot {
            None => Euler {
                x: Deg(0.0),
                y: Deg(0.0),
                z: Deg(0.0),
            },
            Some(v) => Euler {
                x: Deg(v.x),
                y: Deg(v.y),
                z: Deg(v.z),
            },
        };
        Position {
            x: pos.x,
            y: pos.y,
            z: pos.z,
            rot: euler,
        }
    }
}

impl From<Option<TomlPositionDescription>> for Position {
    fn from(pos: Option<TomlPositionDescription>) -> Self {
        match pos {
            None => Position {
                x: 0.0,
                y: 0.0,
                z: 0.0,
                rot: Euler {
                    x: Deg(0.0),
                    y: Deg(0.0),
                    z: Deg(0.0),
                },
            },
            Some(v) => Position::from(v),
        }
    }
}

#[derive(Clone, Default, PartialEq, Eq, Hash, Copy, Debug)]
pub struct RangeCopy<Idx> {
    pub start: Idx,
    pub end: Idx,
}

#[derive(Clone, Debug)]
pub struct Mesh {
    pub index_buffer: Arc<Buffer>,
    pub index_count: usize,
    pub index_format: wgpu::IndexFormat,
    pub vertex_buffer: Arc<Buffer>,
    pub uniform_buffer: Arc<Buffer>,
    pub bind_group: Arc<BindGroup>,
    pub color: wgpu::Color,
}

#[derive(Clone, Debug)]
pub struct Physics {
    pub rigid_body: RigidBody,
    pub rigid_body_handle: Option<RigidBodyHandle>,
}

#[derive(Clone)]
pub struct Collider {
    pub collider: r3dCollider,
    pub collider_handle: Option<ColliderHandle>,
}
