//! Keyboard event subscription handlers.

use crate::message::Message;
use iced::keyboard::Key;
use iced::window;
use iced::{Event, Subscription};

/// Emits keyboard shortcut messages for global editor actions.
pub fn shortcuts() -> Subscription<Message> {
    iced::event::listen_with(|event, _status, _id| match event {
        Event::Keyboard(iced::keyboard::Event::KeyPressed { key, modifiers, .. }) => {
            let primary = modifiers.command() || modifiers.control();
            let navigation_msg = match &key {
                Key::Named(iced::keyboard::key::Named::ArrowUp) => {
                    Some(Message::FuzzyFinderNavigate(-1))
                }
                Key::Named(iced::keyboard::key::Named::ArrowDown) => {
                    Some(Message::FuzzyFinderNavigate(1))
                }
                Key::Named(iced::keyboard::key::Named::Enter) => Some(Message::FuzzyFinderSelect),
                _ => None,
            };

            if navigation_msg.is_some() {
                return navigation_msg;
            }

            if let Key::Character(c) = &key {
                if modifiers.command() && modifiers.control() && c.as_str() == "f" {
                    return Some(Message::ToggleFullscreen(window::Mode::Fullscreen));
                } else if primary && modifiers.shift() {
                    match c.as_str() {
                        "v" | "V" => return Some(Message::PreviewMarkdown),
                        "f" | "F" => return Some(Message::ToggleFuzzyFinder),
                        "p" | "P" => return Some(Message::ToggleCommandPalette),
                        "s" | "S" => return Some(Message::ToggleSettings),
                        "o" | "O" => return Some(Message::OpenFolderDialog),
                        _ => {}
                    }
                } else if primary {
                    match c.as_str() {
                        "b" | "r" => return Some(Message::ToggleSidebar),
                        "o" | "O" => return Some(Message::OpenFileOrFolder),
                        "w" | "W" => return Some(Message::CloseActiveTab),
                        "s" | "S" => return Some(Message::SaveFile),
                        "t" | "T" => return Some(Message::ToggleFileFinder),
                        "j" | "J" => return Some(Message::ToggleTerminal),
                        "f" | "F" => return Some(Message::ToggleFindReplace),
                        "n" | "N" => return Some(Message::NewFile),
                        "1" => return Some(Message::SelectTabByIndex(0)),
                        "2" => return Some(Message::SelectTabByIndex(1)),
                        "3" => return Some(Message::SelectTabByIndex(2)),
                        "4" => return Some(Message::SelectTabByIndex(3)),
                        "5" => return Some(Message::SelectTabByIndex(4)),
                        "6" => return Some(Message::SelectTabByIndex(5)),
                        "7" => return Some(Message::SelectTabByIndex(6)),
                        "8" => return Some(Message::SelectTabByIndex(7)),
                        "9" => return Some(Message::SelectTabByIndex(8)),
                        _ => {}
                    }
                }
            }

            if !modifiers.command() && !modifiers.control() {
                if let Key::Named(iced::keyboard::key::Named::Escape) = key {
                    return Some(Message::EscapePressed);
                }
            }

            None
        }
        _ => None,
    })
}

pub fn modifier_state() -> Subscription<Message> {
    iced::event::listen_with(|event, _status, _id| match event {
        Event::Keyboard(iced::keyboard::Event::ModifiersChanged(modifiers)) => {
            Some(Message::ModifierStateChanged(modifiers))
        }
        Event::Keyboard(iced::keyboard::Event::KeyPressed { modifiers, .. }) => {
            Some(Message::ModifierStateChanged(modifiers))
        }
        Event::Keyboard(iced::keyboard::Event::KeyReleased { modifiers, .. }) => {
            Some(Message::ModifierStateChanged(modifiers))
        }

        _ => None,
    })
}
