pub mod editor;
pub mod buffer;
pub mod insert;
pub mod delete;
pub mod search;
pub mod replace;
pub mod helper;
pub mod cursor;
pub mod clipboard;
pub mod operator;
pub mod file;
pub mod status;

#[cfg(test)]
mod editor_test;

use crate::state::EditorState;
use crate::action::Action;

pub enum EventResult {
    Continue,
    Exit,
}

pub fn reduce(editor: &mut EditorState, action: Action) -> EventResult {
    // The yank flash lasts exactly until the next keypress: clear it here, before
    // dispatch, so a fresh yank in this same call can re-arm it for one frame.
    editor.yank_highlight = None;

    // Dispatch to buffer reducer for editing actions
    match action {
        Action::InsertChar(c) => {
            match editor.mode {
                crate::state::EditorMode::Edit => insert::handle_insert_char(editor, c),
                crate::state::EditorMode::Search => {
                    search::update_search_buffer(editor, c);
                    EventResult::Continue
                }
                crate::state::EditorMode::Replace => {
                    replace::update_replace_buffer(editor, c);
                    EventResult::Continue
                }
                crate::state::EditorMode::Save | crate::state::EditorMode::Open | crate::state::EditorMode::Quit => {
                    file::update_filename_buffer(editor, c)
                }
                crate::state::EditorMode::Goto => {
                    if c.is_ascii_digit() {
                        editor.goto_line_buffer.push(c);
                    }
                    EventResult::Continue
                }
                _ => EventResult::Continue,
            }
        }
        Action::InsertString(s) => clipboard::paste_string(editor, &s),
        Action::Enter => {
            // Enter is special, handled in both but depends on mode
            // insert reducer handles Insert/Edit mode Enter
            // editor reducer handles others
            match editor.mode {
                crate::state::EditorMode::Edit => {
                    insert::handle_enter(editor)
                }
                crate::state::EditorMode::Search => {
                    search::apply_search_next(editor)
                }
                crate::state::EditorMode::Replace => {
                    replace::apply_replace_current(editor)
                }
                _ => {
                    editor::apply_editor_event(editor, &action)
                }
            }
        }
        Action::Backspace => {
            match editor.mode {
                // Glide `X` deletes the char before the cursor (mirror of `x`).
                crate::state::EditorMode::Edit | crate::state::EditorMode::Glide => delete::handle_backspace(editor),
                crate::state::EditorMode::Search => {
                    search::delete_from_search_buffer(editor);
                    EventResult::Continue
                }
                crate::state::EditorMode::Replace => {
                    replace::delete_from_replace_buffer(editor);
                    EventResult::Continue
                }
                crate::state::EditorMode::Save | crate::state::EditorMode::Open | crate::state::EditorMode::Quit => {
                    file::delete_from_filename_buffer(editor)
                }
                crate::state::EditorMode::Goto => {
                    editor.goto_line_buffer.pop();
                    EventResult::Continue
                }
                _ => EventResult::Continue,
            }
        }
        Action::Delete => {
            match editor.mode {
                crate::state::EditorMode::Save | crate::state::EditorMode::Open | crate::state::EditorMode::Quit => {
                    file::delete_char_at_cursor(editor)
                }
                crate::state::EditorMode::Search => {
                    search::delete_search_char_at_cursor(editor);
                    EventResult::Continue
                }
                crate::state::EditorMode::Replace => {
                    replace::delete_replace_char_at_cursor(editor);
                    EventResult::Continue
                }
                _ => delete::handle_delete(editor),
            }
        }
        Action::PasteFromClipboard => clipboard::paste_from_clipboard(editor),
        Action::ReplaceCurrent => replace::apply_replace_current(editor),
        Action::ReplaceAll => replace::apply_replace_all(editor),
        Action::SearchNext => search::apply_search_next(editor),
        Action::SearchPrevious => search::apply_search_previous(editor),
        Action::ToggleSearchMode => search::apply_toggle_search_mode(editor),
        Action::SwitchFocus => replace::apply_switch_focus(editor),
        Action::MoveLeft => {
            match editor.mode {
                crate::state::EditorMode::Save | crate::state::EditorMode::Open | crate::state::EditorMode::Quit => {
                    file::move_filename_cursor_left(editor)
                }
                crate::state::EditorMode::Search => {
                    search::move_search_cursor_left(editor);
                    EventResult::Continue
                }
                crate::state::EditorMode::Replace => {
                    replace::move_replace_cursor_left(editor);
                    EventResult::Continue
                }
                _ => editor::apply_editor_event(editor, &action),
            }
        }
        Action::MoveRight => {
            match editor.mode {
                crate::state::EditorMode::Save | crate::state::EditorMode::Open | crate::state::EditorMode::Quit => {
                    file::move_filename_cursor_right(editor)
                }
                crate::state::EditorMode::Search => {
                    search::move_search_cursor_right(editor);
                    EventResult::Continue
                }
                crate::state::EditorMode::Replace => {
                    replace::move_replace_cursor_right(editor);
                    EventResult::Continue
                }
                _ => editor::apply_editor_event(editor, &action),
            }
        }
        Action::Home => {
            match editor.mode {
                crate::state::EditorMode::Save | crate::state::EditorMode::Open | crate::state::EditorMode::Quit => {
                    file::move_filename_cursor_home(editor)
                }
                crate::state::EditorMode::Search => {
                    search::move_search_cursor_home(editor);
                    EventResult::Continue
                }
                crate::state::EditorMode::Replace => {
                    replace::move_replace_cursor_home(editor);
                    EventResult::Continue
                }
                _ => editor::apply_editor_event(editor, &action),
            }
        }
        Action::End => {
            match editor.mode {
                crate::state::EditorMode::Save | crate::state::EditorMode::Open | crate::state::EditorMode::Quit => {
                    file::move_filename_cursor_end(editor)
                }
                crate::state::EditorMode::Search => {
                    search::move_search_cursor_end(editor);
                    EventResult::Continue
                }
                crate::state::EditorMode::Replace => {
                    replace::move_replace_cursor_end(editor);
                    EventResult::Continue
                }
                _ => editor::apply_editor_event(editor, &action),
            }
        }
        _ => {
            editor::apply_editor_event(editor, &action)
        }
    }
}
