// src/functions/modes/read_only/add_logic_ro.rs
use crate::config::binds::key_sequences::KeySequenceTracker;
use crate::state::pages::add_logic::AddLogicState; // Changed
use crate::state::pages::canvas_state::CanvasState;
use crate::state::app::state::AppState;
use anyhow::Result;

// Word navigation helpers (get_char_type, find_next_word_start, etc.)
// can be kept as they are generic.
#[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 prev_start = find_prev_word_start(text, current_pos);
    if prev_start == 0 { return 0; }
    find_word_end(text, prev_start.saturating_sub(1))
}


/// Executes read-only actions for the AddLogic view canvas.
pub async fn execute_action(
    action: &str,
    app_state: &mut AppState,
    state: &mut AddLogicState,
    ideal_cursor_column: &mut usize,
    key_sequence_tracker: &mut KeySequenceTracker,
    command_message: &mut String,
) -> Result<String> {
    match action {
        "move_up" => {
            key_sequence_tracker.reset();
            let num_fields = AddLogicState::INPUT_FIELD_COUNT;
            if num_fields == 0 { return Ok("No fields.".to_string()); }
            let current_field = state.current_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_cursor_pos = if current_input.is_empty() { 0 } else { current_input.len().saturating_sub(1) };
                let new_pos = (*ideal_cursor_column).min(max_cursor_pos);
                state.set_current_cursor_pos(new_pos);
            } else {
                *command_message = "At top of form.".to_string();
            }
            Ok(command_message.clone())
        }
        "move_down" => {
            key_sequence_tracker.reset();
            let num_fields = AddLogicState::INPUT_FIELD_COUNT;
            if num_fields == 0 { return Ok("No fields.".to_string()); }
            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 = if current_input.is_empty() { 0 } else { current_input.len().saturating_sub(1) };
                let new_pos = (*ideal_cursor_column).min(max_cursor_pos);
                state.set_current_cursor_pos(new_pos);
            } else {
                // Move focus outside canvas when moving down from the last field
                // FIX: Go to ScriptContentPreview instead of SaveButton
                app_state.ui.focus_outside_canvas = true;
                state.last_canvas_field = 2;
                state.current_focus = crate::state::pages::add_logic::AddLogicFocus::ScriptContentPreview; // FIXED!
                *command_message = "Focus moved to script preview".to_string();
            }
            Ok(command_message.clone())
        }
        // ... (rest of the actions remain the same) ...
        "move_first_line" => {
            key_sequence_tracker.reset();
            if AddLogicState::INPUT_FIELD_COUNT > 0 {
                state.set_current_field(0);
                let current_input = state.get_current_input();
                let max_cursor_pos = if current_input.is_empty() { 0 } else { current_input.len().saturating_sub(1) };
                let new_pos = (*ideal_cursor_column).min(max_cursor_pos);
                state.set_current_cursor_pos(new_pos);
                *ideal_cursor_column = new_pos;
            }
            Ok("".to_string())
        }
        "move_last_line" => {
            key_sequence_tracker.reset();
            let num_fields = AddLogicState::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 = if current_input.is_empty() { 0 } else { current_input.len().saturating_sub(1) };
                let new_pos = (*ideal_cursor_column).min(max_cursor_pos);
                state.set_current_cursor_pos(new_pos);
                *ideal_cursor_column = new_pos;
            }
            Ok("".to_string())
        }
        "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;
            Ok("".to_string())
        }
        "move_right" => {
            let current_input = state.get_current_input();
            let current_pos = state.current_cursor_pos();
            if !current_input.is_empty() && current_pos < current_input.len().saturating_sub(1) {
                let new_pos = current_pos + 1;
                state.set_current_cursor_pos(new_pos);
                *ideal_cursor_column = new_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().saturating_sub(1));
                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 && current_pos < current_input.len().saturating_sub(1) {
                    find_word_end(current_input, current_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())
        }
        "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();
            if !current_input.is_empty() {
                let new_pos = current_input.len().saturating_sub(1);
                state.set_current_cursor_pos(new_pos);
                *ideal_cursor_column = new_pos;
            } else {
                state.set_current_cursor_pos(0);
                *ideal_cursor_column = 0;
            }
            Ok("".to_string())
        }
        "enter_edit_mode_before" | "enter_edit_mode_after" | "enter_command_mode" | "exit_highlight_mode" => {
             key_sequence_tracker.reset();
             Ok("Mode change handled by main loop".to_string())
        }
        _ => {
             key_sequence_tracker.reset();
             command_message.clear();
             Ok(format!("Unknown read-only action: {}", action))
        },
    }
}

