// src/modes/canvas/edit.rs use crate::config::binds::config::Config; use crate::services::grpc_client::GrpcClient; use crate::state::pages::{auth::{AuthState, RegisterState}}; use crate::state::canvas_state::CanvasState; use crate::state::pages::form::FormState; use crate::functions::modes::edit::{auth_e, form_e}; use crate::modes::handlers::event::EventOutcome; use crate::state::state::AppState; use crossterm::event::{KeyCode, KeyEvent}; pub async fn handle_edit_event( key: KeyEvent, config: &Config, form_state: &mut FormState, auth_state: &mut AuthState, register_state: &mut RegisterState, ideal_cursor_column: &mut usize, command_message: &mut String, current_position: &mut u64, total_count: u64, grpc_client: &mut GrpcClient, app_state: &AppState, ) -> Result> { // Global command mode check if let Some("enter_command_mode") = config.get_action_for_key_in_mode( &config.keybindings.global, key.code, key.modifiers ) { *command_message = "Switching to Command Mode...".to_string(); return Ok(command_message.clone()); } // Common actions (save/revert) if let Some(action) = config.get_action_for_key_in_mode( &config.keybindings.common, key.code, key.modifiers ) { if matches!(action, "save" | "revert") { let message = if app_state.ui.show_login { auth_e::execute_common_action( action, auth_state, // Concrete AuthState grpc_client, current_position, total_count ).await } else if app_state.ui.show_register { auth_e::execute_common_action( action, register_state, grpc_client, current_position, total_count ).await } else { form_e::execute_common_action( action, form_state, // Concrete FormState grpc_client, current_position, total_count ).await .map(|outcome| match outcome { EventOutcome::Ok(msg) => msg, EventOutcome::Exit(msg) => format!("Exit requested: {}", msg), EventOutcome::DataSaved(save_outcome, msg) => format!("Data saved ({:?}): {}", save_outcome, msg), EventOutcome::ButtonSelected { context, index } => { "Unexpected action in edit mode".to_string() } }) }?; return Ok(message); } } // Edit-specific actions if let Some(action) = config.get_edit_action_for_key(key.code, key.modifiers) { // --- Autocomplete Dropdown Interaction Handling (PRIORITY) --- if app_state.ui.show_register && register_state.current_field() == 4 && register_state.show_role_suggestions { match action { "suggestion_down" => { 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 }); return Ok("Suggestion changed".to_string()); } "suggestion_up" => { 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) }); return Ok("Suggestion changed".to_string()); } "select_suggestion" => { if let Some(selected_index) = register_state.selected_suggestion_index { if let Some(selected_role) = register_state.role_suggestions.get(selected_index) { register_state.role = selected_role.clone(); // Hide dropdown after selection register_state.show_role_suggestions = false; register_state.selected_suggestion_index = None; register_state.role_suggestions.clear(); // Move cursor to end of selected role let new_cursor_pos = register_state.role.len(); register_state.set_current_cursor_pos(new_cursor_pos); *ideal_cursor_column = new_cursor_pos; return Ok(format!("Selected role: {}", register_state.role)); } } return Ok("No suggestion selected".to_string()); } "hide_suggestions" => { register_state.show_role_suggestions = false; register_state.selected_suggestion_index = None; return Ok("Suggestions hidden".to_string()); } // Allow field navigation to hide suggestions "next_field" | "prev_field" => { register_state.show_role_suggestions = false; register_state.selected_suggestion_index = None; // Fall through to execute the navigation action below } _ => {} // Other edit actions might be ignored while dropdown is active } } // --- End Autocomplete Interaction Handling --- // --- Autocomplete Handling for Role Field --- if app_state.ui.show_register && register_state.current_field() == 4 { match action { "suggestion_down" if register_state.show_role_suggestions => { let max_index = register_state.role_suggestions.len() - 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 }); return Ok("Suggestion changed".to_string()); } "suggestion_up" if register_state.show_role_suggestions => { let max_index = register_state.role_suggestions.len() - 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 - 1 }); return Ok("Suggestion changed".to_string()); } "select_suggestion" if register_state.show_role_suggestions => { if let Some(selected_index) = register_state.selected_suggestion_index { if let Some(selected_role) = register_state.role_suggestions.get(selected_index) { register_state.role = selected_role.clone(); register_state.show_role_suggestions = false; register_state.selected_suggestion_index = None; register_state.role_suggestions.clear(); // Optionally move to next field or exit edit mode here return Ok(format!("Selected role: {}", register_state.role)); } } return Ok("No suggestion selected".to_string()); } "hide_suggestions" => { register_state.show_role_suggestions = false; register_state.selected_suggestion_index = None; return Ok("Suggestions hidden".to_string()); } // Let other edit actions (like move_*) fall through for the role field if desired // Or explicitly handle them here if they should behave differently _ => {} } } // --- End Autocomplete Handling --- return if app_state.ui.show_login { auth_e::execute_edit_action( action, key, auth_state, ideal_cursor_column, grpc_client, current_position, total_count ).await } else if app_state.ui.show_register { auth_e::execute_edit_action( action, key, register_state, ideal_cursor_column, grpc_client, current_position, total_count ).await } else { form_e::execute_edit_action( action, key, form_state, ideal_cursor_column, grpc_client, current_position, total_count ).await }; } // Character insertion if let KeyCode::Char(_) = key.code { // --- Autocomplete Trigger on Char Insert --- let is_role_field = app_state.ui.show_register && register_state.current_field() == 4; let result = // Store result before potential update // --- End Autocomplete Trigger --- return if app_state.ui.show_login { auth_e::execute_edit_action( "insert_char", key, auth_state, ideal_cursor_column, grpc_client, current_position, total_count ).await } else if app_state.ui.show_register { auth_e::execute_edit_action( "insert_char", key, register_state, ideal_cursor_column, grpc_client, current_position, total_count ).await } else { form_e::execute_edit_action( "insert_char", key, form_state, ideal_cursor_column, grpc_client, current_position, total_count ).await }; // After character insertion/deletion, update suggestions if it was the role field if is_role_field { register_state.update_role_suggestions(); } return result; // Return the result from execute_edit_action } // Handle Backspace/Delete for Autocomplete Trigger if matches!(key.code, KeyCode::Backspace | KeyCode::Delete) { let is_role_field = app_state.ui.show_register && register_state.current_field() == 4; let action_str = if key.code == KeyCode::Backspace { "backspace" } else { "delete_char" }; // Execute the action first let result = if app_state.ui.show_register { auth_e::execute_edit_action( action_str, key, register_state, ideal_cursor_column, grpc_client, current_position, total_count ).await } else { // Handle for login/form if needed, assuming auth_e covers RegisterState Ok("Action not applicable here".to_string()) // Placeholder }?; if is_role_field { register_state.update_role_suggestions(); } return Ok(result); } Ok(command_message.clone()) }