// src/functions/modes/edit/auth_e.rs

use crate::services::grpc_client::GrpcClient;
use crate::state::pages::canvas_state::CanvasState;
use crate::state::pages::form::FormState;
use crate::state::pages::auth::RegisterState;
use crate::state::app::state::AppState;
use crate::tui::functions::common::form::{revert, save};
use crossterm::event::{KeyCode, KeyEvent};
use std::any::Any;
use anyhow::Result;

pub async fn execute_common_action<S: CanvasState + Any>(
    action: &str,
    state: &mut S,
    grpc_client: &mut GrpcClient,
    app_state: &AppState,
    current_position: &mut u64,
    total_count: u64,
) -> Result<String> {
    match action {
        "save" | "revert" => {
            if !state.has_unsaved_changes() {
                return Ok("No changes to save or revert.".to_string());
            }
            if let Some(form_state) =
                (state as &mut dyn Any).downcast_mut::<FormState>()
            {
                match action {
                    "save" => {
                        let outcome = save(
                            app_state,
                            form_state,
                            grpc_client,
                        )
                        .await?;
                        let message = format!("Save successful: {:?}", outcome); // Simple message for now
                        Ok(message)
                    }
                    "revert" => {
                        revert(
                            form_state,
                            grpc_client,
                        )
                        .await
                    }
                    _ => unreachable!(),
                }
            } else {
                Ok(format!(
                    "Action '{}' not implemented for this state type.",
                    action
                ))
            }
        }
        _ => Ok(format!("Common action '{}' not handled here.", action)),
    }
}

pub async fn execute_edit_action<S: CanvasState + Any + Send>(
    action: &str,
    key: KeyEvent,
    state: &mut S,
    ideal_cursor_column: &mut usize,
) -> Result<String> {
    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("working?".to_string())
        }

        "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 = state.fields().len();
            if num_fields > 0 {
                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_pos = current_input.len();
                state.set_current_cursor_pos(
                    (*ideal_cursor_column).min(max_pos),
                );
            }
            Ok("".to_string())
        }

        "prev_field" => {
            let num_fields = state.fields().len();
            if num_fields > 0 {
                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_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 num_fields = state.fields().len();
            if num_fields > 0 {
                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_pos = current_input.len();
                state.set_current_cursor_pos(
                    (*ideal_cursor_column).min(max_pos),
                );
            }
            Ok("".to_string())
        }

        "move_down" => {
            let num_fields = state.fields().len();
            if num_fields > 0 {
                let new_field = (state.current_field() + 1).min(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_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" => {
            let num_fields = state.fields().len();
            if num_fields > 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("Moved to first field".to_string())
        }

        "move_last_line" => {
            let num_fields = state.fields().len();
            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("Moved to last field".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("Moved to previous word end".to_string())
        }

        // --- Autocomplete Actions ---
        "suggestion_down" | "suggestion_up" | "select_suggestion" | "exit_suggestion_mode" => {
            // Attempt to downcast to RegisterState to handle suggestion logic here
            if let Some(register_state) = (state as &mut dyn Any).downcast_mut::<RegisterState>() {
                // Only handle if it's the role field (index 4)
                if register_state.current_field() == 4 {
                    match action {
                        "suggestion_down" if register_state.in_suggestion_mode => {
                            let max_index = register_state.role_suggestions.len().saturating_sub(1);
                            let current_index = register_state.selected_suggestion_index.unwrap_or(0);
                            register_state.selected_suggestion_index = Some(if current_index >= max_index { 0 } else { current_index + 1 });
                            Ok("Suggestion changed down".to_string())
                        }
                        "suggestion_up" if register_state.in_suggestion_mode => {
                            let max_index = register_state.role_suggestions.len().saturating_sub(1);
                            let current_index = register_state.selected_suggestion_index.unwrap_or(0);
                            register_state.selected_suggestion_index = Some(if current_index == 0 { max_index } else { current_index.saturating_sub(1) });
                            Ok("Suggestion changed up".to_string())
                        }
                        "select_suggestion" if register_state.in_suggestion_mode => {
                            if let Some(index) = register_state.selected_suggestion_index {
                                if let Some(selected_role) = register_state.role_suggestions.get(index).cloned() {
                                    register_state.role = selected_role.clone(); // Update the role field
                                    register_state.in_suggestion_mode = false; // Exit suggestion mode
                                    register_state.show_role_suggestions = false; // Hide suggestions
                                    register_state.selected_suggestion_index = None; // Clear selection
                                    Ok(format!("Selected role: {}", selected_role)) // Return success message
                                } else {
                                    Ok("Selected suggestion index out of bounds.".to_string()) // Error case
                                }
                            } else {
                                Ok("No suggestion selected".to_string())
                            }
                        }
                        "exit_suggestion_mode" => { // Handle Esc or other conditions
                            register_state.show_role_suggestions = false;
                            register_state.selected_suggestion_index = None;
                            register_state.in_suggestion_mode = false;
                            Ok("Suggestions hidden".to_string())
                        }
                        _ => {
                            // Action is suggestion-related but state doesn't match (e.g., not in suggestion mode)
                            Ok("Suggestion action ignored: State mismatch.".to_string())
                        }
                    }
                } else {
                    // It's RegisterState, but not the role field
                    Ok("Suggestion action ignored: Not on role field.".to_string())
                 }
            } else {
                // Downcast failed - this action is only for RegisterState
                Ok(format!("Action '{}' not applicable for this state type.", action))
            }
        }
        // --- End Autocomplete Actions ---


        _ => Ok(format!("Unknown or unhandled edit action: {}", action)),
    }
}

#[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
    }
}
