use std::path::PathBuf;

use gilrs::Event as GilEvent;
use legion::world::SubWorld;
use legion::*;
use winit_24::dpi::{PhysicalPosition, PhysicalSize, LogicalPosition};
use winit_24::event::DeviceEvent::MouseMotion;
use winit_24::event::{AxisId, DeviceEvent, DeviceId, ElementState, Event, KeyboardInput, ModifiersState, MouseButton, MouseScrollDelta, StartCause, Touch, TouchPhase, WindowEvent, VirtualKeyCode};
use winit_24::window::{Theme, WindowId, Window};

use crate::camera::{Camera, CameraController};
use crate::owned_event::OwnedWindowEvent::MouseWheel;
use std::sync::{Mutex, Arc};
use std::cmp::Ordering;
use imgui::Io;
use crate::imgui_supp::imgui_support::{ImguiContext, ImguiPlatform};

#[derive(Clone)]
pub enum OwnedUIEvent<T> {
    UIEvent(T),
}

#[derive(Clone)]
pub enum OwnedEventExtension {
    /// Custom events here
    MouseHeldEvent {},
    KeyHeldEvent {},
    GamepadEvent {
        gil_event: GilEvent,
    },
}

#[derive(Clone, Debug)]
pub enum OwnedEvent<T> {
    /// Custom events here
    MouseHeldEvent {},
    KeyHeldEvent {},
    GamepadEvent {
        gil_event: GilEvent,
    },

    /// Winit events here
    NewEvents(StartCause),
    WindowEvent {
        window_id: WindowId,
        event: OwnedWindowEvent,
    },
    DeviceEvent {
        device_id: DeviceId,
        event: DeviceEvent,
    },
    UserEvent(T),
    Suspended,
    Resumed,
    MainEventsCleared,
    RedrawRequested(WindowId),
    RedrawEventsCleared,
    LoopDestroyed,
}

impl<T> From<Event<'_, T>> for OwnedEvent<T> {
    fn from(event: Event<T>) -> Self {
        match event {
            Event::NewEvents(cause) => OwnedEvent::NewEvents(cause),
            Event::WindowEvent {
                window_id: window_id,
                event: event,
            } => OwnedEvent::WindowEvent {
                window_id: window_id,
                event: match event {
                    WindowEvent::AxisMotion {
                        device_id,
                        axis,
                        value,
                    } => OwnedWindowEvent::AxisMotion {
                        device_id,
                        axis,
                        value,
                    },
                    WindowEvent::Resized(physical_size) => OwnedWindowEvent::Resized(physical_size),
                    WindowEvent::Moved(physical_position) => {
                        OwnedWindowEvent::Moved(physical_position)
                    }
                    WindowEvent::CloseRequested => OwnedWindowEvent::CloseRequested,
                    WindowEvent::Destroyed => OwnedWindowEvent::Destroyed,
                    WindowEvent::DroppedFile(path_buf) => OwnedWindowEvent::DroppedFile(path_buf),
                    WindowEvent::HoveredFile(path_buf) => OwnedWindowEvent::HoveredFile(path_buf),
                    WindowEvent::HoveredFileCancelled => OwnedWindowEvent::HoveredFileCancelled,
                    WindowEvent::ReceivedCharacter(char) => {
                        OwnedWindowEvent::ReceivedCharacter(char)
                    }
                    WindowEvent::Focused(bool) => OwnedWindowEvent::Focused(bool),
                    WindowEvent::KeyboardInput {
                        device_id: device_id,
                        input: input,
                        is_synthetic: is_synthetic,
                    } => OwnedWindowEvent::KeyboardInput {
                        device_id,
                        input,
                        is_synthetic,
                    },
                    WindowEvent::ModifiersChanged(modifiers_state) => {
                        OwnedWindowEvent::ModifiersChanged(modifiers_state)
                    }
                    WindowEvent::CursorMoved {
                        device_id: device_id,
                        position: position,
                        modifiers: modifiers,
                    } => OwnedWindowEvent::CursorMoved {
                        device_id,
                        position,
                        modifiers,
                    },
                    WindowEvent::CursorEntered {
                        device_id: device_id,
                    } => OwnedWindowEvent::CursorEntered { device_id },
                    WindowEvent::CursorLeft {
                        device_id: device_id,
                    } => OwnedWindowEvent::CursorLeft { device_id },
                    WindowEvent::MouseWheel {
                        device_id: device_id,
                        delta: delta,
                        phase: phase,
                        modifiers: modifiers,
                    } => OwnedWindowEvent::MouseWheel {
                        device_id,
                        delta,
                        phase,
                        modifiers,
                    },
                    WindowEvent::MouseInput {
                        device_id: device_id,
                        state: state,
                        button: button,
                        modifiers: modifiers,
                    } => OwnedWindowEvent::MouseInput {
                        device_id,
                        state,
                        button,
                        modifiers,
                    },
                    WindowEvent::TouchpadPressure {
                        device_id: device_id,
                        pressure: pressure,
                        stage: stage,
                    } => OwnedWindowEvent::TouchpadPressure {
                        device_id,
                        pressure,
                        stage,
                    },
                    WindowEvent::Touch(touch) => OwnedWindowEvent::Touch(touch),
                    WindowEvent::ScaleFactorChanged {
                        scale_factor: scale_factor,
                        new_inner_size: new_inner_size,
                    } => OwnedWindowEvent::ScaleFactorChanged {
                        scale_factor,
                        new_inner_size: PhysicalSize {
                            width: new_inner_size.width,
                            height: new_inner_size.height,
                        },
                    },
                    WindowEvent::ThemeChanged(theme) => OwnedWindowEvent::ThemeChanged(theme),
                },
            },
            Event::DeviceEvent {
                device_id: device_id,
                event: event,
            } => OwnedEvent::DeviceEvent { device_id, event },
            Event::UserEvent(user_event) => OwnedEvent::UserEvent(user_event),
            Event::Suspended => OwnedEvent::Suspended,
            Event::Resumed => OwnedEvent::Resumed,
            Event::MainEventsCleared => OwnedEvent::MainEventsCleared,
            Event::RedrawRequested(window_id) => OwnedEvent::RedrawRequested(window_id),
            Event::RedrawEventsCleared => OwnedEvent::RedrawEventsCleared,
            Event::LoopDestroyed => OwnedEvent::LoopDestroyed,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum OwnedWindowEvent {
    Resized(PhysicalSize<u32>),
    Moved(PhysicalPosition<i32>),
    CloseRequested,
    Destroyed,
    DroppedFile(PathBuf),
    HoveredFile(PathBuf),
    HoveredFileCancelled,
    ReceivedCharacter(char),
    Focused(bool),
    KeyboardInput {
        device_id: DeviceId,
        input: KeyboardInput,
        is_synthetic: bool,
    },
    ModifiersChanged(ModifiersState),
    CursorMoved {
        device_id: DeviceId,
        position: PhysicalPosition<f64>,
        #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
        modifiers: ModifiersState,
    },
    CursorEntered {
        device_id: DeviceId,
    },
    CursorLeft {
        device_id: DeviceId,
    },
    MouseWheel {
        device_id: DeviceId,
        delta: MouseScrollDelta,
        phase: TouchPhase,
        #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
        modifiers: ModifiersState,
    },
    MouseInput {
        device_id: DeviceId,
        state: ElementState,
        button: MouseButton,
        #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
        modifiers: ModifiersState,
    },
    TouchpadPressure {
        device_id: DeviceId,
        pressure: f32,
        stage: i64,
    },
    AxisMotion {
        device_id: DeviceId,
        axis: AxisId,
        value: f64,
    },
    Touch(Touch),
    ScaleFactorChanged {
        scale_factor: f64,
        new_inner_size: PhysicalSize<u32>,
    },
    ThemeChanged(Theme),
}


/// Because I am a glutton for punishment I am going to just do a mono-event-dispatch-magoooo
#[system]
#[write_component(Camera)]
#[write_component(CameraController)]
pub fn event_dispatch(
    world: &mut SubWorld,
    #[resource] event_stack: &mut Vec<OwnedEvent<OwnedEventExtension>>,
    #[resource] imgui_context: &mut Arc<Mutex<ImguiContext>>,
    #[resource] imgui_platform: &mut Arc<Mutex<ImguiPlatform>>,
    #[resource] winit_window: &mut Window,
) {
    use winit_24::event::Event::DeviceEvent;

    for event in event_stack {

        match event {
            OwnedEvent::DeviceEvent {
                event: winit_24::event::DeviceEvent::MouseMotion { delta },
                ..
            } => {
                let mut query = <(&mut CameraController)>::query();
                for (camera_controller) in query.iter_mut(world) {
                    camera_controller.process_mouse(delta.0, delta.1);
                }

            },
            OwnedEvent::DeviceEvent {
                event: winit_24::event::DeviceEvent::Key(keyboard_input),
                ..
            } => {
                let mut query = <(&mut CameraController)>::query();
                for (camera_controller) in query.iter_mut(world) {
                    camera_controller.process_keyboard(
                        keyboard_input.virtual_keycode.unwrap(),
                        keyboard_input.state,
                    );
                }

                match keyboard_input.virtual_keycode.unwrap() {
                    VirtualKeyCode::R => {
                        if keyboard_input.state == ElementState::Pressed {


                            //winit_window.set_cursor_grab(true);
                        }
                    }
                    VirtualKeyCode::Escape => {
                        if keyboard_input.state == ElementState::Pressed {
                            //winit_window.set_cursor_grab(false);
                        }
                    }
                    _ => ()
                }
            }
            _ => {}
        }

        let mut imgui_context = &mut imgui_context.lock().unwrap().context;
        let mut imgui_platform = &mut imgui_platform.lock().unwrap().platform;

        imgui_platform.handle_event(imgui_context.io_mut(), &winit_window, &event);
    }
}
