use super::context::{self, EditorContext};
use nightshade::prelude::*;

pub enum InputSignal {
    QuitRequested,
    AddPrimitiveRequested(Vec2),
}

pub struct InputResult {
    pub signal: Option<InputSignal>,
    pub tree_dirty: bool,
    pub project_modified: bool,
}

pub fn is_ctrl_pressed(world: &World) -> bool {
    world
        .resources
        .input
        .keyboard
        .is_key_pressed(KeyCode::ControlLeft)
        || world
            .resources
            .input
            .keyboard
            .is_key_pressed(KeyCode::ControlRight)
}

pub fn is_shift_pressed(world: &World) -> bool {
    world
        .resources
        .input
        .keyboard
        .is_key_pressed(KeyCode::ShiftLeft)
        || world
            .resources
            .input
            .keyboard
            .is_key_pressed(KeyCode::ShiftRight)
}

pub fn on_keyboard_input_handler(
    context: &mut EditorContext,
    world: &mut World,
    key_code: KeyCode,
    key_state: KeyState,
) -> InputResult {
    let mut tree_dirty = false;
    let mut project_modified = false;

    if key_state == KeyState::Pressed {
        let ctrl_pressed = is_ctrl_pressed(world);

        let shift_pressed = is_shift_pressed(world);

        let in_modal_transform =
            context.transform_edit.modal.operation != context::TransformOperation::None;

        match key_code {
            KeyCode::Escape => {
                if in_modal_transform {
                    super::gizmo::cancel_modal_transform(context, world);
                }
            }
            KeyCode::KeyQ => {
                if !in_modal_transform {
                    return InputResult {
                        signal: Some(InputSignal::QuitRequested),
                        tree_dirty,
                        project_modified,
                    };
                }
            }
            KeyCode::KeyZ if ctrl_pressed => {
                let changed = super::selection::undo_with_selection_update(context, world);
                tree_dirty |= changed;
                project_modified |= changed;
            }
            KeyCode::KeyY if ctrl_pressed => {
                let changed = super::selection::redo_with_selection_update(context, world);
                tree_dirty |= changed;
                project_modified |= changed;
            }
            KeyCode::Tab if !in_modal_transform => {
                context.coordinate_space = match context.coordinate_space {
                    context::CoordinateSpace::World => context::CoordinateSpace::Local,
                    context::CoordinateSpace::Local => context::CoordinateSpace::World,
                };
                super::gizmo::update_gizmo_mode_for_coordinate_space(context, world);
            }
            KeyCode::KeyC if ctrl_pressed && !in_modal_transform => {
                super::selection::copy_selection_to_clipboard(context, world);
            }
            KeyCode::KeyV if ctrl_pressed && !in_modal_transform => {
                let changed = super::selection::paste_from_clipboard(context, world);
                tree_dirty |= changed;
                project_modified |= changed;
            }
            KeyCode::KeyG if !ctrl_pressed => {
                super::gizmo::start_modal_transform(
                    context,
                    world,
                    context::TransformOperation::Grab,
                );
            }
            KeyCode::KeyR if !ctrl_pressed => {
                super::gizmo::start_modal_transform(
                    context,
                    world,
                    context::TransformOperation::Rotate,
                );
            }
            KeyCode::KeyS if !ctrl_pressed && !in_modal_transform => {
                super::gizmo::start_modal_transform(
                    context,
                    world,
                    context::TransformOperation::Scale,
                );
            }
            KeyCode::KeyX if !ctrl_pressed => {
                if in_modal_transform {
                    context.transform_edit.modal.constraint = context::TransformConstraint::X;
                } else {
                    let changed = super::selection::delete_selection(context, world);
                    tree_dirty |= changed;
                    project_modified |= changed;
                }
            }
            KeyCode::KeyY if !ctrl_pressed && in_modal_transform => {
                context.transform_edit.modal.constraint = context::TransformConstraint::Y;
            }
            KeyCode::KeyZ if !ctrl_pressed && in_modal_transform => {
                context.transform_edit.modal.constraint = context::TransformConstraint::Z;
            }
            KeyCode::Enter if in_modal_transform => {
                project_modified |= super::gizmo::confirm_modal_transform(context, world);
            }
            KeyCode::KeyA if !ctrl_pressed && !in_modal_transform => {
                let mouse_pos = world.resources.input.mouse.position;
                return InputResult {
                    signal: Some(InputSignal::AddPrimitiveRequested(mouse_pos)),
                    tree_dirty,
                    project_modified,
                };
            }
            KeyCode::KeyA if ctrl_pressed && !in_modal_transform => {
                super::selection::select_all(context, world);
            }
            KeyCode::KeyD if shift_pressed && !in_modal_transform => {
                let changed = super::selection::duplicate_selection(context, world);
                tree_dirty |= changed;
                project_modified |= changed;
            }
            KeyCode::Numpad1 if !in_modal_transform => {
                super::camera_controls::set_camera_view(
                    world,
                    super::camera_controls::CameraView::Front,
                );
            }
            KeyCode::Numpad3 if !in_modal_transform => {
                super::camera_controls::set_camera_view(
                    world,
                    super::camera_controls::CameraView::Right,
                );
            }
            KeyCode::Numpad7 if !in_modal_transform => {
                super::camera_controls::set_camera_view(
                    world,
                    super::camera_controls::CameraView::Top,
                );
            }
            KeyCode::Numpad5 if !in_modal_transform => {
                super::camera_controls::toggle_camera_orthographic(world);
            }
            KeyCode::Numpad0 if !in_modal_transform => {
                super::camera_controls::toggle_camera_mode(world, &mut context.camera_mode);
            }
            _ => {
                if in_modal_transform && !ctrl_pressed {
                    project_modified |=
                        super::gizmo::handle_numeric_input_for_transform(context, key_code, world);
                }
            }
        }
    }
    InputResult {
        signal: None,
        tree_dirty,
        project_modified,
    }
}
