use std::sync::Arc;
use crate::canvas::*;
use crate::canvas::managed::handles::{CanvasFontHandle, CanvasImageHandle, CanvasTextureHandle, Handle};
use crate::canvas::canvas_frame::{Drawable, Eventable, Updatable};
use crate::util::vertex::{VertexTypeContainer, TextureVertex3D, Vertex3D};
use winit::event::{DeviceEvent, MouseButton, ElementState, Event, WindowEvent};

///
#[derive(Debug, Clone)]
pub struct Sprite {
    pub position: (f32, f32),
    pub size: (f32, f32),
    depth: f32,
    texture_handle: Arc<CanvasTextureHandle>,
}

/// Container class which implements drawable.
impl Sprite {
    fn generate_verts(window_size: (u32, u32), position: (f32, f32), size: (f32, f32), depth: f32) -> Vec<TextureVertex3D> {

        let ss_position = (
            position.0 / window_size.0 as f32 - 1.0,
            position.1 / window_size.1 as f32 - 1.0
        );

        let ss_size = (
            size.0 / window_size.0 as f32,
            size.1 / window_size.1 as f32
        );

        vec![
            TextureVertex3D {
                v_position: [ss_position.0, ss_position.1, depth],                   // top left
                ti_position: [-0.0, -0.0],
            },
            TextureVertex3D {
                v_position: [ss_position.0, ss_position.1 + ss_size.1, depth],          // bottom left
                ti_position: [-0.0, 1.0],
            },
            TextureVertex3D {
                v_position: [ss_position.0 + ss_size.0, ss_position.1 + ss_size.1, depth], // bottom right
                ti_position: [1.0, 1.0],
            },
            TextureVertex3D {
                v_position: [ss_position.0, ss_position.1, depth],                   // top left
                ti_position: [-0.0, -0.0],
            },
            TextureVertex3D {
                v_position: [ss_position.0 + ss_size.0, ss_position.1 + ss_size.1, depth], // bottom right
                ti_position: [1.0, 1.0],
            },
            TextureVertex3D {
                v_position: [ss_position.0 + ss_size.0, ss_position.1, depth],          // top right
                ti_position: [1.0, -0.0],
            },
        ]
    }

    ///
    pub fn new(position: (f32, f32),
               size: (f32, f32),
               depth: u32,
               texture_handle: Arc<CanvasTextureHandle>) -> Sprite {
        let normalized_depth = (depth as f32 / 255.0);

        Sprite {
            position: position,
            size: size,
            depth: normalized_depth,
            texture_handle: texture_handle.clone(),
        }
    }
}

impl Drawable for Sprite {
    fn get(&self, window_size: (u32, u32)) -> Vec<VertexTypeContainer> {
        vec![
            VertexTypeContainer::TextureType(
                Sprite::generate_verts(window_size, self.position, self.size, self.depth),
                self.texture_handle.clone())
        ]
    }
}

impl<T> Eventable<T> for Sprite {
    fn notify(&mut self, event: &Event<T>) -> () {
        match event {
            Event::WindowEvent { event: WindowEvent::MouseInput { device_id, state, button, modifiers }, .. } => {
                match button {
                    MouseButton::Left => {
                        if *state == ElementState::Pressed {
                            self.position = (self.position.0, self.position.1 + 0.1);
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

impl Updatable for Sprite {
    fn update(&mut self, delta_time: f32) -> () {

    }
}
