// src/modes/general/command_navigation.rs
use crate::config::binds::config::Config;
use crate::modes::handlers::event::EventOutcome;
use anyhow::Result;
use common::proto::komp_ac::table_definition::ProfileTreeResponse;
use crossterm::event::{KeyCode, KeyEvent};
use std::collections::{HashMap, HashSet};

#[derive(Debug, Clone, PartialEq)]
pub enum NavigationType {
    FindFile,
    TableTree,
}

#[derive(Debug, Clone)]
pub struct TableDependencyGraph {
    all_tables: HashSet<String>,
    dependents_map: HashMap<String, Vec<String>>,
    root_tables: Vec<String>,
}

impl TableDependencyGraph {
    pub fn from_profile_tree(profile_tree: &ProfileTreeResponse) -> Self {
        let mut dependents_map: HashMap<String, Vec<String>> = HashMap::new();
        let mut all_tables_set: HashSet<String> = HashSet::new();
        let mut table_dependencies: HashMap<String, Vec<String>> = HashMap::new();

        for profile in &profile_tree.profiles {
            for table in &profile.tables {
                all_tables_set.insert(table.name.clone());
                table_dependencies.insert(table.name.clone(), table.depends_on.clone());

                for dependency_name in &table.depends_on {
                    dependents_map
                        .entry(dependency_name.clone())
                        .or_default()
                        .push(table.name.clone());
                }
            }
        }

        let root_tables: Vec<String> = all_tables_set
            .iter()
            .filter(|name| {
                table_dependencies
                    .get(*name)
                    .map_or(true, |deps| deps.is_empty())
            })
            .cloned()
            .collect();

        let mut sorted_root_tables = root_tables;
        sorted_root_tables.sort();

        for dependents_list in dependents_map.values_mut() {
            dependents_list.sort();
        }

        Self {
            all_tables: all_tables_set,
            dependents_map,
            root_tables: sorted_root_tables,
        }
    }

    pub fn get_dependent_children(&self, path: &str) -> Vec<String> {
        if path.is_empty() {
            return self.root_tables.clone();
        }

        let path_segments: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
        if let Some(last_segment_name) = path_segments.last() {
            if self.all_tables.contains(*last_segment_name) {
                return self
                    .dependents_map
                    .get(*last_segment_name)
                    .cloned()
                    .unwrap_or_default();
            }
        }
        Vec::new()
    }
}


// ... (NavigationState struct and its new(), activate_*, deactivate(), add_char(), remove_char(), move_*, autocomplete_selected(), get_display_input() methods are unchanged) ...
pub struct NavigationState {
    pub active: bool,
    pub input: String,
    pub selected_index: Option<usize>,
    pub filtered_options: Vec<(usize, String)>,
    pub navigation_type: NavigationType,
    pub current_path: String,
    pub graph: Option<TableDependencyGraph>,
    pub all_options: Vec<String>,
}

impl NavigationState {
    pub fn new() -> Self {
        Self {
            active: false,
            input: String::new(),
            selected_index: None,
            filtered_options: Vec::new(),
            navigation_type: NavigationType::FindFile,
            current_path: String::new(),
            graph: None,
            all_options: Vec::new(),
        }
    }

    pub fn activate_find_file(&mut self, options: Vec<String>) {
        self.active = true;
        self.navigation_type = NavigationType::FindFile;
        self.all_options = options;
        self.input.clear();
        self.current_path.clear();
        self.graph = None;
        self.update_filtered_options();
    }

    pub fn activate_table_tree(&mut self, graph: TableDependencyGraph) {
        self.active = true;
        self.navigation_type = NavigationType::TableTree;
        self.graph = Some(graph);
        self.input.clear();
        self.current_path.clear();
        self.update_options_for_path();
    }

    pub fn deactivate(&mut self) {
        self.active = false;
        self.input.clear();
        self.all_options.clear();
        self.filtered_options.clear();
        self.selected_index = None;
        self.current_path.clear();
        self.graph = None;
    }

    pub fn add_char(&mut self, c: char) {
        match self.navigation_type {
            NavigationType::FindFile => {
                self.input.push(c);
                self.update_filtered_options();
            }
            NavigationType::TableTree => {
                if c == '/' {
                    if !self.input.is_empty() {
                        if self.current_path.is_empty() {
                            self.current_path = self.input.clone();
                        } else {
                            self.current_path.push('/');
                            self.current_path.push_str(&self.input);
                        }
                        self.input.clear();
                        self.update_options_for_path();
                    }
                } else {
                    self.input.push(c);
                    self.update_filtered_options();
                }
            }
        }
    }

    pub fn remove_char(&mut self) {
        match self.navigation_type {
            NavigationType::FindFile => {
                self.input.pop();
                self.update_filtered_options();
            }
            NavigationType::TableTree => {
                if self.input.is_empty() {
                    if !self.current_path.is_empty() {
                        if let Some(last_slash_idx) = self.current_path.rfind('/') {
                            self.input = self.current_path[last_slash_idx + 1..].to_string();
                            self.current_path = self.current_path[..last_slash_idx].to_string();
                        } else {
                            self.input = self.current_path.clone();
                            self.current_path.clear();
                        }
                        self.update_options_for_path();
                        self.update_filtered_options();
                    }
                } else {
                    self.input.pop();
                    self.update_filtered_options();
                }
            }
        }
    }

    pub fn move_up(&mut self) {
        if self.filtered_options.is_empty() {
            self.selected_index = None;
            return;
        }
        self.selected_index = match self.selected_index {
            Some(0) => Some(self.filtered_options.len() - 1),
            Some(current) => Some(current - 1),
            None => Some(self.filtered_options.len() - 1),
        };
    }

    pub fn move_down(&mut self) {
        if self.filtered_options.is_empty() {
            self.selected_index = None;
            return;
        }
        self.selected_index = match self.selected_index {
            Some(current) if current >= self.filtered_options.len() - 1 => Some(0),
            Some(current) => Some(current + 1),
            None => Some(0),
        };
    }

    pub fn get_selected_option_str(&self) -> Option<&str> {
        self.selected_index
            .and_then(|idx| self.filtered_options.get(idx))
            .map(|(_, option_str)| option_str.as_str())
    }

    pub fn autocomplete_selected(&mut self) {
        if let Some(selected_option_str) = self.get_selected_option_str() {
            self.input = selected_option_str.to_string();
            self.update_filtered_options();
        }
    }

    pub fn get_display_input(&self) -> String {
        match self.navigation_type {
            NavigationType::FindFile => self.input.clone(),
            NavigationType::TableTree => {
                if self.current_path.is_empty() {
                    self.input.clone()
                } else {
                    format!("{}/{}", self.current_path, self.input)
                }
            }
        }
    }

    // --- START FIX ---
    pub fn get_selected_value(&self) -> Option<String> {
        match self.navigation_type {
            NavigationType::FindFile => {
                // Return the highlighted option, not the raw input buffer.
                self.get_selected_option_str().map(|s| s.to_string())
            }
            NavigationType::TableTree => {
                self.get_selected_option_str().map(|selected_name| {
                    if self.current_path.is_empty() {
                        selected_name.to_string()
                    } else {
                        format!("{}/{}", self.current_path, selected_name)
                    }
                })
            }
        }
    }
    // --- END FIX ---

    fn update_options_for_path(&mut self) {
        if let NavigationType::TableTree = self.navigation_type {
            if let Some(graph) = &self.graph {
                self.all_options = graph.get_dependent_children(&self.current_path);
            } else {
                self.all_options.clear();
            }
        }
        self.update_filtered_options();
    }

    fn update_filtered_options(&mut self) {
        let filter_text = match self.navigation_type {
            NavigationType::FindFile => &self.input,
            NavigationType::TableTree => &self.input,
        }
        .to_lowercase();

        if filter_text.is_empty() {
            self.filtered_options = self
                .all_options
                .iter()
                .enumerate()
                .map(|(i, opt)| (i, opt.clone()))
                .collect();
        } else {
            self.filtered_options = self
                .all_options
                .iter()
                .enumerate()
                .filter(|(_, opt)| opt.to_lowercase().contains(&filter_text))
                .map(|(i, opt)| (i, opt.clone()))
                .collect();
        }

        if self.filtered_options.is_empty() {
            self.selected_index = None;
        } else {
            self.selected_index = Some(0);
        }
    }
}


pub async fn handle_command_navigation_event(
    navigation_state: &mut NavigationState,
    key: KeyEvent,
    config: &Config,
) -> Result<EventOutcome> {
    if !navigation_state.active {
        return Ok(EventOutcome::Ok(String::new()));
    }

    match key.code {
        KeyCode::Esc => {
            navigation_state.deactivate();
            Ok(EventOutcome::Ok("Navigation cancelled".to_string()))
        }
        KeyCode::Tab => {
            if let Some(selected_opt_str) = navigation_state.get_selected_option_str() {
                if navigation_state.input == selected_opt_str {
                    if navigation_state.navigation_type == NavigationType::TableTree {
                        let path_before_nav = navigation_state.current_path.clone();
                        let input_before_nav = navigation_state.input.clone();
                        navigation_state.add_char('/');
                        if !(navigation_state.input.is_empty() &&
                           (navigation_state.current_path != path_before_nav || !navigation_state.all_options.is_empty())) {
                            if !navigation_state.input.is_empty() && navigation_state.input != input_before_nav {
                                navigation_state.input = input_before_nav;
                                if navigation_state.current_path != path_before_nav {
                                    navigation_state.current_path = path_before_nav;
                                }
                                navigation_state.update_options_for_path();
                            }
                        }
                    }
                } else {
                    navigation_state.autocomplete_selected();
                }
            }
            Ok(EventOutcome::Ok(String::new()))
        }
        KeyCode::Backspace => {
            navigation_state.remove_char();
            Ok(EventOutcome::Ok(String::new()))
        }
        KeyCode::Char(c) => {
            navigation_state.add_char(c);
            Ok(EventOutcome::Ok(String::new()))
        }
        _ => {
            if let Some(action) = config.get_general_action(key.code, key.modifiers) {
                match action {
                    "move_up" => {
                        navigation_state.move_up();
                        Ok(EventOutcome::Ok(String::new()))
                    }
                    "move_down" => {
                        navigation_state.move_down();
                        Ok(EventOutcome::Ok(String::new()))
                    }
                    "select" => {
                        if let Some(selected_value) = navigation_state.get_selected_value() {
                            let outcome = match navigation_state.navigation_type {
                                // --- START FIX ---
                                NavigationType::FindFile => {
                                    // The purpose of this palette is to select a table.
                                    // Emit a TableSelected event instead of a generic Ok message.
                                    EventOutcome::TableSelected {
                                        path: selected_value,
                                    }
                                }
                                // --- END FIX ---
                                NavigationType::TableTree => {
                                    EventOutcome::TableSelected {
                                        path: selected_value,
                                    }
                                }
                            };
                            navigation_state.deactivate();
                            Ok(outcome)
                        } else {
                            Ok(EventOutcome::Ok("No selection".to_string()))
                        }
                    }
                    _ => Ok(EventOutcome::Ok(String::new())),
                }
            } else {
                Ok(EventOutcome::Ok(String::new()))
            }
        }
    }
}
