// src/functions/modes/read_only/add_table_ro.rs
use crate::config::binds::key_sequences::KeySequenceTracker;
use crate::state::pages::add_table::AddTableState;
use crate::state::app::state::AppState;
use canvas::canvas::CanvasState;
use anyhow::Result;

// Re-use word navigation helpers if they are public or move them to a common module
// For now, duplicating them here for simplicity. Consider refactoring later.
#[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
}

// Note: find_prev_word_end might need adjustments based on desired behavior.
// This version finds the end of the word *before* the previous word start.
fn find_prev_word_end(text: &str, current_pos: usize) -> usize {
    let prev_start = find_prev_word_start(text, current_pos);
    if prev_start == 0 { return 0; }
    // Find the end of the word that starts at prev_start - 1
    find_word_end(text, prev_start.saturating_sub(1))
}


/// Executes read-only actions for the AddTable view canvas.
pub async fn execute_action(
    action: &str,
    app_state: &mut AppState, // Needed for focus_outside_canvas
    state: &mut AddTableState,
    ideal_cursor_column: &mut usize,
    key_sequence_tracker: &mut KeySequenceTracker,
    command_message: &mut String, // Keep for potential messages
) -> Result<String> {
    // Use the CanvasState trait methods implemented for AddTableState
    match action {
        "move_up" => {
            key_sequence_tracker.reset();
            let num_fields = AddTableState::INPUT_FIELD_COUNT;
            if num_fields == 0 {
                *command_message = "No fields.".to_string();
                return Ok(command_message.clone());
            }
            let current_field = state.current_field(); // Gets the index (0, 1, or 2)

            if current_field > 0 {
                // This handles moving from field 2 -> 1, or 1 -> 0
                let new_field = current_field - 1;
                state.set_current_field(new_field);
                let current_input = state.get_current_input();
                let max_cursor_pos = current_input.len(); // Allow cursor at end
                let new_pos = (*ideal_cursor_column).min(max_cursor_pos);
                state.set_current_cursor_pos(new_pos);
                *ideal_cursor_column = new_pos; // Update ideal column as cursor moved
                *command_message = "".to_string(); // Clear message for successful internal navigation
            } else {
                // current_field is 0 (InputTableName), and user pressed Up.
                // Forbid moving up. Do not change focus or cursor.
                *command_message = "At top of form.".to_string();
            }
            Ok(command_message.clone())
        }
        "move_down" => {
            key_sequence_tracker.reset();
            let num_fields = AddTableState::INPUT_FIELD_COUNT;
            if num_fields == 0 {
                *command_message = "No fields.".to_string();
                return Ok(command_message.clone());
            }
            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_cursor_pos = current_input.len(); // Allow cursor at end
                let new_pos = (*ideal_cursor_column).min(max_cursor_pos);
                state.set_current_cursor_pos(new_pos);
                *ideal_cursor_column = new_pos; // Update ideal column
                *command_message = "".to_string();
            } else {
                // Move focus outside canvas when moving down from the last field
                app_state.ui.focus_outside_canvas = true;
                // Set focus to the first element outside canvas (AddColumnButton)
                state.current_focus =
                    crate::state::pages::add_table::AddTableFocus::AddColumnButton;
                *command_message = "Focus moved below canvas".to_string();
            }
            Ok(command_message.clone())
        }
        // ... (other actions like "move_first_line", "move_left", etc. remain the same) ...
        "move_first_line" => {
            key_sequence_tracker.reset();
            if AddTableState::INPUT_FIELD_COUNT > 0 {
                state.set_current_field(0);
                let current_input = state.get_current_input();
                let max_cursor_pos = current_input.len();
                let new_pos = (*ideal_cursor_column).min(max_cursor_pos);
                state.set_current_cursor_pos(new_pos);
                *ideal_cursor_column = new_pos; // Update ideal column
            }
            *command_message = "".to_string();
            Ok(command_message.clone())
        }
        "move_last_line" => {
            key_sequence_tracker.reset();
            let num_fields = AddTableState::INPUT_FIELD_COUNT;
            if num_fields > 0 {
                let last_field_index = num_fields - 1;
                state.set_current_field(last_field_index);
                let current_input = state.get_current_input();
                let max_cursor_pos = current_input.len();
                let new_pos = (*ideal_cursor_column).min(max_cursor_pos);
                state.set_current_cursor_pos(new_pos);
                *ideal_cursor_column = new_pos; // Update ideal column
            }
            *command_message = "".to_string();
            Ok(command_message.clone())
        }
        "move_left" => {
            let current_pos = state.current_cursor_pos();
            let new_pos = current_pos.saturating_sub(1);
            state.set_current_cursor_pos(new_pos);
            *ideal_cursor_column = new_pos;
            *command_message = "".to_string();
            Ok(command_message.clone())
        }
        "move_right" => {
            let current_input = state.get_current_input();
            let current_pos = state.current_cursor_pos();
            // Allow moving cursor one position past the end
            if current_pos < current_input.len() {
                let new_pos = current_pos + 1;
                state.set_current_cursor_pos(new_pos);
                *ideal_cursor_column = new_pos;
            }
            *command_message = "".to_string();
            Ok(command_message.clone())
        }
        "move_word_next" => {
            let current_input = state.get_current_input();
            let new_pos = find_next_word_start(
                current_input,
                state.current_cursor_pos(),
            );
            let final_pos = new_pos.min(current_input.len()); // Allow cursor at end
            state.set_current_cursor_pos(final_pos);
            *ideal_cursor_column = final_pos;
            *command_message = "".to_string();
            Ok(command_message.clone())
        }
        "move_word_end" => {
            let current_input = state.get_current_input();
            let current_pos = state.current_cursor_pos();
            let new_pos = find_word_end(current_input, current_pos);
            // If find_word_end returns current_pos, try starting search from next char
            let final_pos =
                if new_pos == current_pos && current_pos < current_input.len() {
                    find_word_end(current_input, current_pos + 1)
                } else {
                    new_pos
                };
            let max_valid_index = current_input.len(); // Allow cursor at end
            let clamped_pos = final_pos.min(max_valid_index);
            state.set_current_cursor_pos(clamped_pos);
            *ideal_cursor_column = clamped_pos;
            *command_message = "".to_string();
            Ok(command_message.clone())
        }
        "move_word_prev" => {
            let current_input = state.get_current_input();
            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;
            *command_message = "".to_string();
            Ok(command_message.clone())
        }
        "move_word_end_prev" => {
            let current_input = state.get_current_input();
            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;
            *command_message = "".to_string();
            Ok(command_message.clone())
        }
        "move_line_start" => {
            state.set_current_cursor_pos(0);
            *ideal_cursor_column = 0;
            *command_message = "".to_string();
            Ok(command_message.clone())
        }
        "move_line_end" => {
            let current_input = state.get_current_input();
            let new_pos = current_input.len(); // Allow cursor at end
            state.set_current_cursor_pos(new_pos);
            *ideal_cursor_column = new_pos;
            *command_message = "".to_string();
            Ok(command_message.clone())
        }
        // Actions handled by main event loop (mode changes)
        "enter_edit_mode_before" | "enter_edit_mode_after"
        | "enter_command_mode" | "exit_highlight_mode" => {
            key_sequence_tracker.reset();
            // These actions are primarily mode changes handled by the main event loop.
            // The message here might be overridden by the main loop's message for mode change.
            *command_message = "Mode change initiated".to_string();
            Ok(command_message.clone())
        }
        _ => {
            key_sequence_tracker.reset();
            *command_message =
                format!("Unknown read-only action: {}", action);
            Ok(command_message.clone())
        }
    }
}

