// src/state/app/state.rs

use anyhow::Result;
use common::proto::komp_ac::table_definition::ProfileTreeResponse;
// NEW: Import the types we need for the cache
use common::proto::komp_ac::table_structure::TableStructureResponse;
use crate::modes::handlers::mode_manager::AppMode;
use crate::search::state::SearchState;
use crate::ui::handlers::context::DialogPurpose;
use crate::config::binds::Config;
use crate::pages::forms::FormState;
use canvas::FormEditor;
use crate::dialog::DialogState;
use std::collections::HashMap;
use std::env;
use std::sync::Arc;
#[cfg(feature = "ui-debug")]
use std::time::Instant;

pub struct UiState {
    pub show_sidebar: bool,
    pub show_buffer_list: bool,
    pub show_intro: bool,
    pub show_admin: bool,
    pub show_add_table: bool,
    pub show_add_logic: bool,
    pub show_form: bool,
    pub show_login: bool,
    pub show_register: bool,
    pub show_search_palette: bool,
    pub focus_outside_canvas: bool,
    pub dialog: DialogState,
}

#[cfg(feature = "ui-debug")]
#[derive(Debug, Clone)]
pub struct DebugState {
    pub displayed_message: String,
    pub is_error: bool,
    pub display_start_time: Instant,
}

pub struct AppState {
    // Core editor state
    pub current_dir: String,
    pub profile_tree: ProfileTreeResponse,
    pub selected_profile: Option<String>,
    pub current_mode: AppMode,
    pub current_view_profile_name: Option<String>,
    pub current_view_table_name: Option<String>,

    // NEW: The "Rulebook" cache. We use Arc for efficient sharing.
    pub schema_cache: HashMap<String, Arc<TableStructureResponse>>,

    pub focused_button_index: usize,
    pub pending_table_structure_fetch: Option<(String, String)>,

    pub search_state: Option<SearchState>,

    // UI preferences
    pub ui: UiState,

    pub form_editor: HashMap<String, FormEditor<FormState>>, // key = "profile/table"

    #[cfg(feature = "ui-debug")]
    pub debug_state: Option<DebugState>,
}

impl AppState {
    pub fn new() -> Result<Self> {
        let current_dir = env::current_dir()?.to_string_lossy().to_string();
        Ok(AppState {
            current_dir,
            profile_tree: ProfileTreeResponse::default(),
            selected_profile: None,
            current_view_profile_name: None,
            current_view_table_name: None,
            current_mode: AppMode::General,
            schema_cache: HashMap::new(), // NEW: Initialize the cache
            focused_button_index: 0,
            pending_table_structure_fetch: None,
            search_state: None,
            ui: UiState::default(),
            form_editor: HashMap::new(),

            #[cfg(feature = "ui-debug")]
            debug_state: None,
        })
    }

    // --- ALL YOUR EXISTING METHODS ARE UNTOUCHED ---

    pub fn update_mode(&mut self, mode: AppMode) {
        self.current_mode = mode;
    }

    pub fn set_current_view_table(&mut self, profile_name: String, table_name: String) {
        self.current_view_profile_name = Some(profile_name);
        self.current_view_table_name = Some(table_name);
    }

    /// Returns true if the current view's editor is in Edit mode.
    /// Uses current_view_profile_name/current_view_table_name to build the path.
    pub fn is_canvas_edit_mode(&self) -> bool {
        if let (Some(profile), Some(table)) =
            (self.current_view_profile_name.as_ref(), self.current_view_table_name.as_ref())
        {
            let path = format!("{}/{}", profile, table);
            if let Some(editor) = self.form_editor.get(&path) {
                return matches!(editor.mode(), canvas::AppMode::Edit);
            }
        }
        false
    }

    pub fn is_canvas_edit_mode_at(&self, path: &str) -> bool {
        self.form_editor
            .get(path)
            .map(|e| matches!(e.mode(), canvas::AppMode::Edit))
            .unwrap_or(false)
    }

    // Mutable editor accessor
    pub fn editor_for_path(&mut self, path: &str) -> Option<&mut FormEditor<FormState>> {
        self.form_editor.get_mut(path)
    }

    // Mutable FormState accessor
    pub fn form_state_for_path(&mut self, path: &str) -> Option<&mut FormState> {
        self.form_editor
            .get_mut(path)
            .map(|e| e.data_provider_mut())
    }

    // Immutable editor accessor
    pub fn editor_for_path_ref(&self, path: &str) -> Option<&FormEditor<FormState>> {
        self.form_editor.get(path)
    }

    // Immutable FormState accessor
    pub fn form_state_for_path_ref(&self, path: &str) -> Option<&FormState> {
        self.form_editor.get(path).map(|e| e.data_provider())
    }

    pub fn ensure_form_editor<F>(&mut self, path: &str, config: &Config, loader: F)
    where
        F: FnOnce() -> FormState,
    {
        if !self.form_editor.contains_key(path) {
            let mut editor = FormEditor::new(loader());
            editor.set_keymap(config.build_canvas_keymap());
            self.form_editor.insert(path.to_string(), editor);
        }
    }
}

impl Default for UiState {
    fn default() -> Self {
        Self {
            show_sidebar: false,
            show_intro: true,
            show_admin: false,
            show_add_table: false,
            show_add_logic: false,
            show_form: false,
            show_login: false,
            show_register: false,
            show_buffer_list: true,
            show_search_palette: false, // ADDED
            focus_outside_canvas: false,
            dialog: DialogState::default(),
        }
    }
}
