// src/functions/modes/edit/add_table_e.rs
use crate::state::pages::add_table::AddTableState;
use crossterm::event::{KeyCode, KeyEvent};
use canvas::canvas::CanvasState;
use anyhow::Result;

#[derive(PartialEq)]
enum CharType {
    Whitespace,
    Alphanumeric,
    Punctuation,
}

fn get_char_type(c: char) -> CharType {
    if c.is_whitespace() {
        CharType::Whitespace
    } else if c.is_alphanumeric() {
        CharType::Alphanumeric
    } else {
        CharType::Punctuation
    }
}

fn find_next_word_start(text: &str, current_pos: usize) -> usize {
    let chars: Vec<char> = text.chars().collect();
    let len = chars.len();
    if len == 0 || current_pos >= len {
        return len;
    }

    let mut pos = current_pos;
    let initial_type = get_char_type(chars[pos]);

    while pos < len && get_char_type(chars[pos]) == initial_type {
        pos += 1;
    }

    while pos < len && get_char_type(chars[pos]) == CharType::Whitespace {
        pos += 1;
    }

    pos
}

fn find_word_end(text: &str, current_pos: usize) -> usize {
    let chars: Vec<char> = text.chars().collect();
    let len = chars.len();
    if len == 0 {
        return 0;
    }

    let mut pos = current_pos.min(len - 1);

    if get_char_type(chars[pos]) == CharType::Whitespace {
        pos = find_next_word_start(text, pos);
    }

    if pos >= len {
        return len.saturating_sub(1);
    }

    let word_type = get_char_type(chars[pos]);
    while pos < len && get_char_type(chars[pos]) == word_type {
        pos += 1;
    }

    pos.saturating_sub(1).min(len.saturating_sub(1))
}

fn find_prev_word_start(text: &str, current_pos: usize) -> usize {
    let chars: Vec<char> = text.chars().collect();
    if chars.is_empty() || current_pos == 0 {
        return 0;
    }

    let mut pos = current_pos.saturating_sub(1);

    while pos > 0 && get_char_type(chars[pos]) == CharType::Whitespace {
        pos -= 1;
    }

    if pos == 0 && get_char_type(chars[pos]) == CharType::Whitespace {
        return 0;
    }

    let word_type = get_char_type(chars[pos]);
    while pos > 0 && get_char_type(chars[pos - 1]) == word_type {
        pos -= 1;
    }

    pos
}

fn find_prev_word_end(text: &str, current_pos: usize) -> usize {
    let chars: Vec<char> = text.chars().collect();
    let len = chars.len();
    if len == 0 || current_pos == 0 {
        return 0;
    }

    let mut pos = current_pos.saturating_sub(1);

    while pos > 0 && get_char_type(chars[pos]) == CharType::Whitespace {
        pos -= 1;
    }

    if pos == 0 && get_char_type(chars[pos]) == CharType::Whitespace {
        return 0;
    }
    if pos == 0 && get_char_type(chars[pos]) != CharType::Whitespace {
        return 0;
    }

    let word_type = get_char_type(chars[pos]);
    while pos > 0 && get_char_type(chars[pos - 1]) == word_type {
        pos -= 1;
    }

    while pos > 0 && get_char_type(chars[pos - 1]) == CharType::Whitespace {
        pos -= 1;
    }

    if pos > 0 {
        pos - 1
    } else {
        0
    }
}

/// Executes edit actions for the AddTable view canvas.
pub async fn execute_edit_action(
    action: &str,
    key: KeyEvent, // Needed for insert_char
    state: &mut AddTableState,
    ideal_cursor_column: &mut usize,
    // Add other params like grpc_client if needed for future actions (e.g., validation)
) -> Result<String> {
    // Use the CanvasState trait methods implemented for AddTableState
    match action {
        "insert_char" => {
            if let KeyCode::Char(c) = key.code {
                let cursor_pos = state.current_cursor_pos();
                let field_value = state.get_current_input_mut();
                let mut chars: Vec<char> = field_value.chars().collect();
                if cursor_pos <= chars.len() {
                    chars.insert(cursor_pos, c);
                    *field_value = chars.into_iter().collect();
                    state.set_current_cursor_pos(cursor_pos + 1);
                    state.set_has_unsaved_changes(true);
                    *ideal_cursor_column = state.current_cursor_pos();
                }
            } else {
                return Ok("Error: insert_char called without a char key.".to_string());
            }
            Ok("".to_string()) // No message needed for char insertion
        }
        "delete_char_backward" => {
            if state.current_cursor_pos() > 0 {
                let cursor_pos = state.current_cursor_pos();
                let field_value = state.get_current_input_mut();
                let mut chars: Vec<char> = field_value.chars().collect();
                if cursor_pos <= chars.len() {
                    chars.remove(cursor_pos - 1);
                    *field_value = chars.into_iter().collect();
                    let new_pos = cursor_pos - 1;
                    state.set_current_cursor_pos(new_pos);
                    state.set_has_unsaved_changes(true);
                    *ideal_cursor_column = new_pos;
                }
            }
            Ok("".to_string())
        }
        "delete_char_forward" => {
            let cursor_pos = state.current_cursor_pos();
            let field_value = state.get_current_input_mut();
            let mut chars: Vec<char> = field_value.chars().collect();
            if cursor_pos < chars.len() {
                chars.remove(cursor_pos);
                *field_value = chars.into_iter().collect();
                state.set_has_unsaved_changes(true);
                *ideal_cursor_column = cursor_pos;
            }
            Ok("".to_string())
        }
        "next_field" => {
            let num_fields = AddTableState::INPUT_FIELD_COUNT;
            if num_fields > 0 {
                let current_field = state.current_field();
                let last_field_index = num_fields - 1;
                // Prevent cycling forward
                if current_field < last_field_index {
                    state.set_current_field(current_field + 1);
                }
                let current_input = state.get_current_input();
                let max_pos = current_input.len();
                state.set_current_cursor_pos((*ideal_cursor_column).min(max_pos));
            }
            Ok("".to_string())
        }
        "prev_field" => {
            let num_fields = AddTableState::INPUT_FIELD_COUNT;
            if num_fields > 0 {
                let current_field = state.current_field();
                if current_field > 0 {
                    state.set_current_field(current_field - 1);
                }
                let current_input = state.get_current_input();
                let max_pos = current_input.len();
                state.set_current_cursor_pos((*ideal_cursor_column).min(max_pos));
            }
            Ok("".to_string())
        }
        "move_left" => {
            let new_pos = state.current_cursor_pos().saturating_sub(1);
            state.set_current_cursor_pos(new_pos);
            *ideal_cursor_column = new_pos;
            Ok("".to_string())
        }
        "move_right" => {
            let current_input = state.get_current_input();
            let current_pos = state.current_cursor_pos();
            if current_pos < current_input.len() {
                let new_pos = current_pos + 1;
                state.set_current_cursor_pos(new_pos);
                *ideal_cursor_column = new_pos;
            }
            Ok("".to_string())
        }
        "move_up" => {
            let current_field = state.current_field();
            // Prevent moving up from the first field
            if current_field > 0 {
                let new_field = current_field - 1;
                state.set_current_field(new_field);
                let current_input = state.get_current_input();
                let max_pos = current_input.len();
                state.set_current_cursor_pos((*ideal_cursor_column).min(max_pos));
            }
            Ok("ahoj".to_string())
        }
        "move_down" => {
            let num_fields = AddTableState::INPUT_FIELD_COUNT;
            if num_fields > 0 {
                let current_field = state.current_field();
                let last_field_index = num_fields - 1;
                if current_field < last_field_index {
                    let new_field = current_field + 1;
                    state.set_current_field(new_field);
                    let current_input = state.get_current_input();
                    let max_pos = current_input.len();
                    state.set_current_cursor_pos((*ideal_cursor_column).min(max_pos));
                }
            }
            Ok("".to_string())
        }
        "move_line_start" => {
            state.set_current_cursor_pos(0);
            *ideal_cursor_column = 0;
            Ok("".to_string())
        }
        "move_line_end" => {
            let current_input = state.get_current_input();
            let new_pos = current_input.len();
            state.set_current_cursor_pos(new_pos);
            *ideal_cursor_column = new_pos;
            Ok("".to_string())
        }
        "move_first_line" => {
            if AddTableState::INPUT_FIELD_COUNT > 0 {
                state.set_current_field(0);
                let current_input = state.get_current_input();
                let max_pos = current_input.len();
                state.set_current_cursor_pos((*ideal_cursor_column).min(max_pos));
            }
            Ok("".to_string())
        }
        "move_last_line" => {
            let num_fields = AddTableState::INPUT_FIELD_COUNT;
            if num_fields > 0 {
                let new_field = num_fields - 1;
                state.set_current_field(new_field);
                let current_input = state.get_current_input();
                let max_pos = current_input.len();
                state.set_current_cursor_pos((*ideal_cursor_column).min(max_pos));
            }
            Ok("".to_string())
        }
        "move_word_next" => {
            let current_input = state.get_current_input();
            if !current_input.is_empty() {
                let new_pos = find_next_word_start(current_input, state.current_cursor_pos());
                let final_pos = new_pos.min(current_input.len());
                state.set_current_cursor_pos(final_pos);
                *ideal_cursor_column = final_pos;
            }
            Ok("".to_string())
        }
        "move_word_end" => {
            let current_input = state.get_current_input();
            if !current_input.is_empty() {
                let current_pos = state.current_cursor_pos();
                let new_pos = find_word_end(current_input, current_pos);

                let final_pos = if new_pos == current_pos {
                    find_word_end(current_input, new_pos + 1)
                } else {
                    new_pos
                };

                let max_valid_index = current_input.len().saturating_sub(1);
                let clamped_pos = final_pos.min(max_valid_index);
                state.set_current_cursor_pos(clamped_pos);
                *ideal_cursor_column = clamped_pos;
            }
            Ok("".to_string())
        }
        "move_word_prev" => {
            let current_input = state.get_current_input();
            if !current_input.is_empty() {
                let new_pos = find_prev_word_start(current_input, state.current_cursor_pos());
                state.set_current_cursor_pos(new_pos);
                *ideal_cursor_column = new_pos;
            }
            Ok("".to_string())
        }
        "move_word_end_prev" => {
            let current_input = state.get_current_input();
            if !current_input.is_empty() {
                let new_pos = find_prev_word_end(current_input, state.current_cursor_pos());
                state.set_current_cursor_pos(new_pos);
                *ideal_cursor_column = new_pos;
            }
            Ok("".to_string())
        }
        // Actions handled by main event loop (mode changes, save, revert)
        "exit_edit_mode" | "save" | "revert" => {
            Ok("Action handled by main loop".to_string())
        }
        _ => Ok(format!("Unknown or unhandled edit action: {}", action)),
    }
}
