// src/tui/functions/common/add_table.rs
use crate::state::pages::add_table::{
    AddTableFocus, AddTableState, ColumnDefinition, IndexDefinition,
};
use crate::services::GrpcClient;
use anyhow::{anyhow, Result};
use common::proto::komp_ac::table_definition::{
    PostTableDefinitionRequest,
    ColumnDefinition as ProtoColumnDefinition,
    TableLink as ProtoTableLink,
};
use tracing::debug;

/// Handles the logic for adding a column when the "Add" button is activated.
///
/// Takes the mutable state and command message string.
/// Returns `Some(AddTableFocus)` indicating the desired focus state after a successful add,
/// or `None` if the action failed (e.g., validation error).
pub fn handle_add_column_action(
    add_table_state: &mut AddTableState,
    command_message: &mut String,
) -> Option<AddTableFocus> {

    // Trim and create owned Strings from inputs
    let table_name_in = add_table_state.table_name_input.trim();
    let column_name_in = add_table_state.column_name_input.trim();
    let column_type_in = add_table_state.column_type_input.trim(); 

    // Validate all inputs needed for this combined action
    let has_table_name = !table_name_in.is_empty();
    let has_column_name = !column_name_in.is_empty();
    let has_column_type = !column_type_in.is_empty();

    match (has_table_name, has_column_name, has_column_type) {
        // Case 1: Both column fields have input (Table name is optional here)
        (_, true, true) => {
            let mut msg = String::new();
            // Optionally update table name if provided
            if has_table_name {
                add_table_state.table_name = table_name_in.to_string();
                msg.push_str(&format!("Table name set to '{}'. ", add_table_state.table_name));
            }
            // Add the column
            let new_column = ColumnDefinition {
                name: column_name_in.to_string(),
                data_type: column_type_in.to_string(),
                selected: false,
            };
            add_table_state.columns.push(new_column.clone()); // Clone for msg
            msg.push_str(&format!("Column '{}' added.", new_column.name));

            // Add corresponding index definition (initially unselected)
            let new_index = IndexDefinition {
                name: column_name_in.to_string(),
                selected: false,
            };
            add_table_state.indexes.push(new_index);
            *command_message = msg;

            // Clear all inputs and reset cursors
            add_table_state.table_name_input.clear();
            add_table_state.column_name_input.clear();
            add_table_state.column_type_input.clear();
            add_table_state.table_name_cursor_pos = 0;
            add_table_state.column_name_cursor_pos = 0;
            add_table_state.column_type_cursor_pos = 0;
            add_table_state.has_unsaved_changes = true;
            Some(AddTableFocus::InputColumnName) // Focus for next column
        }
        // Case 2: Only one column field has input (Error)
        (_, true, false) | (_, false, true) => {
            *command_message = "Both Column Name and Type are required to add a column.".to_string();
            None // Indicate validation failure
        }
        // Case 3: Only Table name has input (No column input)
        (true, false, false) => {
            add_table_state.table_name = table_name_in.to_string();
            *command_message = format!("Table name set to '{}'.", add_table_state.table_name);
            // Clear only table name input
            add_table_state.table_name_input.clear();
            add_table_state.table_name_cursor_pos = 0;
            add_table_state.has_unsaved_changes = true;
            Some(AddTableFocus::InputTableName) // Keep focus here
        }
        // Case 4: All fields are empty
        (false, false, false) => {
            *command_message = "No input provided.".to_string();
            None
        }
    }
}

/// Handles deleting columns marked as selected in the AddTableState.
pub fn handle_delete_selected_columns(
    add_table_state: &mut AddTableState,
) -> String {
    let initial_count = add_table_state.columns.len();
    // Keep only the columns that are NOT selected
    let initial_selected_indices: std::collections::HashSet<String> = add_table_state
        .columns
        .iter()
        .filter(|col| col.selected)
        .map(|col| col.name.clone())
        .collect();
    add_table_state.columns.retain(|col| !col.selected);
    let deleted_count = initial_count - add_table_state.columns.len();

    if deleted_count > 0 {
        add_table_state.indexes.retain(|index| !initial_selected_indices.contains(&index.name));
        add_table_state.has_unsaved_changes = true;
        // Reset selection highlight as indices have changed
        add_table_state.column_table_state.select(None);
        // Optionally, select the first item if the list is not empty
        // if !add_table_state.columns.is_empty() {
        //     add_table_state.column_table_state.select(Some(0));
        // }
        add_table_state.index_table_state.select(None);
        format!("Deleted {} selected column(s).", deleted_count)
    } else {
        "No columns marked for deletion.".to_string()
    }
}

/// Prepares and sends the request to save the new table definition via gRPC.
pub async fn handle_save_table_action(
    grpc_client: &mut GrpcClient,
    add_table_state: &AddTableState,
) -> Result<String> {
    // --- Basic Validation ---
    if add_table_state.table_name.is_empty() {
        return Err(anyhow!("Table name cannot be empty."));
    }
    if add_table_state.columns.is_empty() {
        return Err(anyhow!("Table must have at least one column."));
    }

    // --- Prepare Proto Data ---
    let proto_columns: Vec<ProtoColumnDefinition> = add_table_state
        .columns
        .iter()
        .map(|col| ProtoColumnDefinition {
            name: col.name.clone(),
            field_type: col.data_type.clone(), // Assuming data_type maps directly
        })
        .collect();

    let proto_indexes: Vec<String> = add_table_state
        .indexes
        .iter()
        .filter(|idx| idx.selected) // Only include selected indexes
        .map(|idx| idx.name.clone())
        .collect();

    let proto_links: Vec<ProtoTableLink> = add_table_state
        .links
        .iter()
        .filter(|link| link.selected) // Only include selected links
        .map(|link| ProtoTableLink {
            linked_table_name: link.linked_table_name.clone(),
            // Assuming 'required' maps directly, adjust if needed
            // For now, the proto only seems to use linked_table_name based on example
            // If your proto evolves, map link.is_required here.
            required: false, // Set based on your proto definition/needs
        })
        .collect();

    // --- Create Request ---
    let request = PostTableDefinitionRequest {
        table_name: add_table_state.table_name.clone(),
        columns: proto_columns,
        indexes: proto_indexes,
        links: proto_links,
        profile_name: add_table_state.profile_name.clone(),
    };

    debug!("Sending PostTableDefinitionRequest: {:?}", request);

    // --- Call gRPC Service ---
    match grpc_client.post_table_definition(request).await {
        Ok(response) => {
            if response.success {
                Ok(format!(
                    "Table '{}' saved successfully.",
                    add_table_state.table_name
                ))
            } else {
                // Use the SQL message from the response if available, otherwise generic error
                let error_message = if !response.sql.is_empty() {
                    format!("Server failed to save table: {}", response.sql)
                } else {
                    "Server failed to save table (unknown reason).".to_string()
                };
                 Err(anyhow!(error_message))
            }
        }
        Err(e) => Err(anyhow!("gRPC call failed: {}", e)),
    }
}
