use anyhow::Result;
use strum::IntoEnumIterator;
use strum_macros::{Display, EnumIter, EnumString};

use crate::app::Status;
use crate::config::Bindings;
use crate::event::EventAction;

/// Different kind of action which can be mapped to a key.
/// All those actions are mapped to a key and this enum
/// makes the junction between received Key events and
/// actions in the application.
#[derive(Clone, Debug, Display, EnumString, EnumIter)]
pub enum ActionMap {
    Action,
    Back,
    Backspace,
    Bulk,
    Cd,
    Chmod,
    ClearFlags,
    CliMenu,
    CloudDrive,
    Compress,
    Context,
    CopyContent,
    CopyFilename,
    CopyFilepath,
    CopyPaste,
    CutPaste,
    Delete,
    DeleteLeft,
    DeleteLine,
    DisplayFlagged,
    End,
    Enter,
    Exec,
    Filter,
    FlagAll,
    FlaggedToClipboard,
    FlaggedFromClipboard,
    FocusGoLeft,
    FocusGoRight,
    FocusGoDown,
    FocusGoUp,
    FuzzyFind,
    FuzzyFindHelp,
    FuzzyFindLine,
    GoRoot,
    GoStart,
    Help,
    History,
    Home,
    KeyHome,
    Log,
    MarksJump,
    MarksNew,
    MoveDown,
    MoveLeft,
    MoveRight,
    MoveUp,
    Mount,
    NextThing,
    NewDir,
    NewFile,
    Nothing,
    NvimFilepicker,
    NvimSetAddress,
    OpenConfig,
    OpenFile,
    OpenAll,
    PageDown,
    PageUp,
    Preview,
    PreviousThing,
    Quit,
    RefreshIfNeeded,
    RefreshView,
    RegexMatch,
    RemoteMount,
    Rename,
    ResetMode,
    ReverseFlags,
    Search,
    SearchNext,
    Shell,
    ShellCommand,
    TempMarksJump,
    TempMarksNew,
    TuiMenu,
    Shortcut,
    Sort,
    Symlink,
    SyncLTR,
    Tab,
    ToggleDisplayFull,
    ToggleDualPane,
    ToggleFlag,
    ToggleHidden,
    TogglePreviewSecond,
    TrashEmpty,
    TrashMoveFile,
    TrashOpen,
    TrashRestoreFile,
    Tree,
    TreeFold,
    TreeFoldAll,
    TreeUnFoldAll,
    ToggleVisual,
    Custom(String),
}

impl ActionMap {
    /// Makes the junction between `Actions` and `Events`.
    /// Every Action links to a different `EventExec` method.
    pub fn matcher(&self, status: &mut Status, binds: &Bindings) -> Result<()> {
        match self {
            Self::Action => EventAction::action(status),
            Self::Back => EventAction::back(status),
            Self::Backspace => EventAction::backspace(status),
            Self::Bulk => EventAction::bulk(status),
            Self::Cd => EventAction::cd(status),
            Self::Chmod => EventAction::chmod(status),
            Self::ClearFlags => EventAction::clear_flags(status),
            Self::CliMenu => EventAction::cli_menu(status),
            Self::CloudDrive => EventAction::cloud_drive(status),
            Self::Compress => EventAction::compress(status),
            Self::Context => EventAction::context(status),
            Self::CopyContent => EventAction::copy_content(status),
            Self::CopyFilename => EventAction::copy_filename(status),
            Self::CopyFilepath => EventAction::copy_filepath(status),
            Self::CopyPaste => EventAction::copy_paste(status),
            Self::CutPaste => EventAction::cut_paste(status),
            Self::Delete => EventAction::delete(status),
            Self::DeleteLeft => EventAction::delete_left(status),
            Self::DeleteLine => EventAction::delete_line(status),
            Self::DisplayFlagged => EventAction::display_flagged(status),
            Self::End => EventAction::end(status),
            Self::Enter => EventAction::enter(status, binds),
            Self::Exec => EventAction::exec(status),
            Self::Filter => EventAction::filter(status),
            Self::FlagAll => EventAction::flag_all(status),
            Self::FlaggedToClipboard => EventAction::flagged_to_clipboard(status),
            Self::FlaggedFromClipboard => EventAction::flagged_from_clipboard(status),
            Self::FocusGoLeft => EventAction::focus_go_left(status),
            Self::FocusGoRight => EventAction::focus_go_right(status),
            Self::FocusGoDown => EventAction::focus_go_down(status),
            Self::FocusGoUp => EventAction::focus_go_up(status),
            Self::FuzzyFind => EventAction::fuzzyfind(status),
            Self::FuzzyFindHelp => EventAction::fuzzyfind_help(status, binds),
            Self::FuzzyFindLine => EventAction::fuzzyfind_line(status),
            Self::GoRoot => EventAction::go_root(status),
            Self::GoStart => EventAction::go_start(status),
            Self::Help => EventAction::help(status, binds),
            Self::History => EventAction::history(status),
            Self::Home => EventAction::home(status),
            Self::KeyHome => EventAction::key_home(status),
            Self::Log => EventAction::log(status),
            Self::MarksJump => EventAction::marks_jump(status),
            Self::MarksNew => EventAction::marks_new(status),
            Self::Mount => EventAction::mount(status),
            Self::MoveDown => EventAction::move_down(status),
            Self::MoveLeft => EventAction::move_left(status),
            Self::MoveRight => EventAction::move_right(status),
            Self::MoveUp => EventAction::move_up(status),
            Self::NextThing => EventAction::next_thing(status),
            Self::NewDir => EventAction::new_dir(status),
            Self::NewFile => EventAction::new_file(status),
            Self::NvimFilepicker => EventAction::nvim_filepicker(status),
            Self::NvimSetAddress => EventAction::set_nvim_server(status),
            Self::OpenConfig => EventAction::open_config(status),
            Self::OpenFile => EventAction::open_file(status),
            Self::OpenAll => EventAction::open_all(status),
            Self::PageDown => EventAction::page_down(status),
            Self::PageUp => EventAction::page_up(status),
            Self::Preview => EventAction::preview(status),
            Self::PreviousThing => EventAction::previous_thing(status),
            Self::Quit => EventAction::quit(status),
            Self::RefreshIfNeeded => EventAction::refresh_if_needed(status),
            Self::RefreshView => EventAction::refresh_view(status),
            Self::RegexMatch => EventAction::regex_match(status),
            Self::RemoteMount => EventAction::remote_mount(status),
            Self::Rename => EventAction::rename(status),
            Self::ResetMode => EventAction::reset_mode(status),
            Self::ReverseFlags => EventAction::reverse_flags(status),
            Self::Search => EventAction::search(status),
            Self::SearchNext => EventAction::search_next(status),
            Self::Shell => EventAction::shell(status),
            Self::ShellCommand => EventAction::shell_command(status),
            Self::Shortcut => EventAction::shortcut(status),
            Self::Sort => EventAction::sort(status),
            Self::Symlink => EventAction::symlink(status),
            Self::SyncLTR => EventAction::sync_ltr(status),
            Self::Tab => EventAction::tab(status),
            Self::TempMarksJump => EventAction::temp_marks_jump(status),
            Self::TempMarksNew => EventAction::temp_marks_new(status),
            Self::ToggleDisplayFull => EventAction::toggle_display_full(status),
            Self::ToggleDualPane => EventAction::toggle_dualpane(status),
            Self::ToggleFlag => EventAction::toggle_flag(status),
            Self::ToggleHidden => EventAction::toggle_hidden(status),
            Self::TogglePreviewSecond => EventAction::toggle_preview_second(status),
            Self::TrashEmpty => EventAction::trash_empty(status),
            Self::TrashMoveFile => EventAction::trash_move_file(status),
            Self::TrashOpen => EventAction::trash_open(status),
            Self::TrashRestoreFile => EventAction::trash_restore(status),
            Self::Tree => EventAction::tree(status),
            Self::TreeFold => EventAction::tree_fold(status),
            Self::TreeFoldAll => EventAction::tree_fold_all(status),
            Self::TreeUnFoldAll => EventAction::tree_unfold_all(status),
            Self::TuiMenu => EventAction::tui_menu(status),
            Self::ToggleVisual => EventAction::visual(status),
            Self::Custom(string) => EventAction::custom(status, string),

            Self::Nothing => Ok(()),
        }
    }

    pub fn description(&self) -> &'static str {
        match self {
            Self::Action => "ACTION",
            Self::Back => "move back to previous dir",
            Self::Backspace => "delete previous char",
            Self::Bulk => "BULK",
            Self::Cd => "CD",
            Self::Chmod => "CHMOD ",
            Self::ClearFlags => "clear flags",
            Self::CliMenu => "CLI APPS",
            Self::Compress => "compress into an archive",
            Self::Context => "CONTEXT",
            Self::CopyContent => "copy text file content to clipbloard",
            Self::CopyFilename => "copy filename to clipboard",
            Self::CopyFilepath => "copy filepath to clipboard",
            Self::CopyPaste => "copy to current dir",
            Self::CloudDrive => "navigate into a cloud drive",
            Self::Custom(_) => "custom command",
            Self::CutPaste => "move to current dir",
            Self::Delete => "delete files permanently",
            Self::DeleteLeft => "delete a word to the left",
            Self::DeleteLine => "delete the whole line / Sync left tab from right tab",
            Self::DisplayFlagged => "FLAGGED",
            Self::End => "go to last line",
            Self::Enter => "Execute mode then NORMAL",
            Self::Exec => "OPEN WITH ",
            Self::Filter => "FILTER ",
            Self::FlagAll => "flag all",
            Self::FlaggedFromClipboard => "flag existing files from primary clipboard",
            Self::FlaggedToClipboard => "copy flagged files to primary clipbloard",
            Self::FocusGoDown => "move focus to bottom",
            Self::FocusGoLeft => "move focus to left",
            Self::FocusGoRight => "move focus to right",
            Self::FocusGoUp => "move focus to up",
            Self::FuzzyFind => "fuzzy finder for file",
            Self::FuzzyFindHelp => "fuzzy finder from help",
            Self::FuzzyFindLine => "fuzzy finder for line",
            Self::GoRoot => "move to root (/)",
            Self::GoStart => "move to starting point",
            Self::Help => "help",
            Self::History => "HISTORY",
            Self::Home => "move to $HOME",
            Self::KeyHome => "go to first line",
            Self::Log => "open the logs",
            Self::MarksJump => "MARKS: Jump",
            Self::MarksNew => "MARKS: Save",
            Self::Mount => "MOUNTS",
            Self::MoveDown => "one line down",
            Self::MoveLeft => "cd to parent directory ",
            Self::MoveRight => "cd to child directory",
            Self::MoveUp => "one line up  ",
            Self::NewDir => "NEWDIR ",
            Self::NewFile => "NEWFILE",
            Self::NextThing => "select next 'thing'",
            Self::Nothing => "do nothing",
            Self::NvimFilepicker => "open in current nvim session",
            Self::NvimSetAddress => "setup the nvim rpc address",
            Self::OpenAll => "open all flagged files",
            Self::OpenConfig => "open the config file",
            Self::OpenFile => {
                "open the selected file with :
    - default       Self::Default
    - audio         Self::Audio
    - images        Self::Bitmap
    - office        Self::Office
    - pdf, ebooks   Self::Readable
    - text          Self::Text
    - video         Self::Video
    - vectorials    Self::Vectorial
    - compressed files are decompressed
    - iso images are mounted"
            }
            Self::PageDown => "10 lines down",
            Self::PageUp => "10 lines up",
            Self::Preview => "preview this file",
            Self::PreviousThing => "select previous 'thing'",
            Self::Quit => "quit",
            Self::RefreshIfNeeded => "refresh the terminal if we have to",
            Self::RefreshView => "refresh view",
            Self::RegexMatch => "REGEXMATCH",
            Self::RemoteMount => "MOUNT REMOTE PATH",
            Self::Rename => "RENAME",
            Self::ResetMode => "NORMAL",
            Self::ReverseFlags => "reverse flags",
            Self::Search => "SEARCH",
            Self::SearchNext => "search next matching element",
            Self::Shell => "shell in current directory",
            Self::ShellCommand => "run a shell command",
            Self::Shortcut => "SHORTCUT",
            Self::Sort => "SORT",
            Self::Symlink => "symlink to current dir",
            Self::SyncLTR => "Sync right tab from left tab path",
            Self::TempMarksJump => "TEMP MARKS: Jump",
            Self::TempMarksNew => "TEMP MARKS: Save",
            Self::Tab => "cycle tab",
            Self::ToggleDisplayFull => "toggle full metadata display of files",
            Self::ToggleDualPane => "toggle dual pane - if the width is sufficiant",
            Self::ToggleFlag => "toggle flag on a file",
            Self::ToggleHidden => "toggle hidden",
            Self::TogglePreviewSecond => "toggle a preview on the second pane",
            Self::TrashEmpty => "Empty the trash",
            Self::TrashMoveFile => "move to trash",
            Self::TrashOpen => "Open the trash (enter to restore, del clear)",
            Self::TrashRestoreFile => "restore the trash file",
            Self::Tree => "Toggle tree mode",
            Self::TreeFold => "Fold a node",
            Self::TreeFoldAll => "Fold every node",
            Self::TreeUnFoldAll => "Unfold every node",
            Self::TuiMenu => "TUI APPS",
            Self::ToggleVisual => "Visual selection",
        }
    }

    pub fn actions_matching(key: String) -> Vec<String> {
        Self::iter()
            .filter(|action| action.to_string().to_lowercase().contains(&key))
            .map(|action| action.to_string())
            .collect()
    }
}
