// src/functions/modes/read_only/form_ro.rs

use crate::config::binds::key_sequences::KeySequenceTracker;
use canvas::canvas::CanvasState;
use anyhow::Result;

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

pub async fn execute_action<S: CanvasState>(
    action: &str,
    state: &mut S,
    ideal_cursor_column: &mut usize,
    key_sequence_tracker: &mut KeySequenceTracker,
    command_message: &mut String,
) -> Result<String> {
    match action {
        "previous_entry" | "next_entry" => {
            key_sequence_tracker.reset();
            Ok(format!(
                "Action '{}' should be handled by context-specific logic",
                action
            ))
        }
        "move_up" => {
            key_sequence_tracker.reset();
            let num_fields = state.fields().len();
            if num_fields == 0 {
                return Ok("No fields to navigate.".to_string());
            }
            let current_field = state.current_field();
            let new_field = current_field.saturating_sub(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);
            Ok("".to_string())
        }
        "move_down" => {
            key_sequence_tracker.reset();
            let num_fields = state.fields().len();
            if num_fields == 0 {
                return Ok("No fields to navigate.".to_string());
            }
            let current_field = state.current_field();
            let new_field = (current_field + 1).min(num_fields - 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);
            Ok("".to_string())
        }
        "move_first_line" => {
            key_sequence_tracker.reset();
            let num_fields = state.fields().len();
            if num_fields == 0 {
                return Ok("No fields to navigate to.".to_string());
            }
            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 = state.fields().len();
            if num_fields == 0 {
                return Ok("No fields to navigate to.".to_string());
            }
            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())
        }
        "exit_edit_mode" => {
            key_sequence_tracker.reset();
            command_message.clear();
            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 {
                    new_pos
                } else {
                    find_word_end(current_input, new_pos + 1)
                };

                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("Moved to previous word end".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())
        }
        _ => {
             key_sequence_tracker.reset();
             Ok(format!("Unknown read-only action: {}", action))
        },
    }
}

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();
    if chars.is_empty() {
        return 0;
    }
    let current_pos = current_pos.min(chars.len());

    if current_pos == chars.len() {
        return current_pos;
    }

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

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

    while pos < chars.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);
    let current_type = get_char_type(chars[pos]);
    if current_type != CharType::Whitespace {
        while pos < len && get_char_type(chars[pos]) == current_type {
            pos += 1;
        }
        return pos.saturating_sub(1);
    }

    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 get_char_type(chars[pos]) != CharType::Whitespace {
        let word_type = get_char_type(chars[pos]);
        while pos > 0 && get_char_type(chars[pos - 1]) == word_type {
            pos -= 1;
        }
    }

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

fn find_prev_word_end(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[0]) == CharType::Whitespace {
        return 0;
    }
     if pos == 0 && get_char_type(chars[0]) != 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
    }
}
