//! Dashboard configuration system
//!
//! Loads and parses menu.toml configuration files to define
//! the dashboard layout, categories, and available actions.

use std::collections::HashMap;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

use anyhow::{Context, Result};
use serde::Deserialize;

/// Main dashboard configuration
#[derive(Debug, Deserialize)]
pub struct DashboardConfig {
    pub dashboard: DashboardInfo,
    pub categories: Vec<MenuCategory>,
    pub actions: Vec<MenuAction>,
    pub quick_actions: Vec<QuickAction>,

    // Processed data (not in TOML)
    #[serde(skip)]
    pub categories_with_actions: Vec<MenuCategory>,
}

/// Dashboard metadata
#[derive(Debug, Deserialize)]
pub struct DashboardInfo {
    #[serde(default)]
    pub title: String,
    pub title_key: Option<String>,
    #[serde(default)]
    pub description: String,
    pub description_key: Option<String>,
    pub version: String,
}

/// Menu category definition
#[derive(Debug, Clone, Deserialize)]
pub struct MenuCategory {
    pub id: String,
    #[serde(default)]
    pub name: String,
    pub name_key: Option<String>,
    #[serde(default)]
    pub description: String,
    pub description_key: Option<String>,
    pub icon: String,
    pub order: u32,

    // Actions belonging to this category (populated after loading)
    #[serde(skip)]
    pub actions: Vec<MenuAction>,
}

/// Menu action definition
#[derive(Debug, Clone, Deserialize)]
pub struct MenuAction {
    pub category: String,
    pub id: String,
    #[serde(default)]
    pub name: String,
    pub name_key: Option<String>,
    #[serde(default)]
    pub description: String,
    pub description_key: Option<String>,
    pub icon: String,
    pub command: String,
    pub shortcut: String,
    pub order: u32,
}

/// Quick action (always visible)
#[derive(Debug, Clone, Deserialize)]
pub struct QuickAction {
    pub id: String,
    #[serde(default)]
    pub name: String,
    pub name_key: Option<String>,
    #[serde(default)]
    pub description: String,
    pub description_key: Option<String>,
    pub icon: String,
    pub command: String,
    pub shortcut: String,
}

impl DashboardConfig {
    /// Load dashboard configuration from menu.toml
    pub fn load(project_root: &Path) -> Result<Self> {
        let config_path = Self::find_config_file(project_root)?;
        let config_content = fs::read_to_string(&config_path)
            .with_context(|| format!("Failed to read config file: {}", config_path.display()))?;

        let mut config: DashboardConfig = toml::from_str(&config_content)
            .context("Failed to parse dashboard configuration TOML")?;

        config.process_configuration()?;
        Ok(config)
    }

    /// Apply translations to the configuration
    pub fn apply_translations(&mut self, translations: &HashMap<String, String>) {
        // Apply dashboard translations
        if let Some(key) = &self.dashboard.title_key {
            if let Some(translated) = translations.get(key) {
                self.dashboard.title = translated.clone();
            }
        }
        if let Some(key) = &self.dashboard.description_key {
            if let Some(translated) = translations.get(key) {
                self.dashboard.description = translated.clone();
            }
        }

        // Apply category translations
        for category in &mut self.categories {
            if let Some(key) = &category.name_key {
                if let Some(translated) = translations.get(key) {
                    category.name = translated.clone();
                }
            }
            if let Some(key) = &category.description_key {
                if let Some(translated) = translations.get(key) {
                    category.description = translated.clone();
                }
            }
        }

        // Apply action translations
        for action in &mut self.actions {
            if let Some(key) = &action.name_key {
                if let Some(translated) = translations.get(key) {
                    action.name = translated.clone();
                }
            }
            if let Some(key) = &action.description_key {
                if let Some(translated) = translations.get(key) {
                    action.description = translated.clone();
                }
            }
        }

        // Apply quick action translations
        for action in &mut self.quick_actions {
            if let Some(key) = &action.name_key {
                if let Some(translated) = translations.get(key) {
                    action.name = translated.clone();
                }
            }
            if let Some(key) = &action.description_key {
                if let Some(translated) = translations.get(key) {
                    action.description = translated.clone();
                }
            }
        }

        // Reprocess configuration to update categories_with_actions
        self.process_configuration().unwrap_or_else(|e| {
            eprintln!(
                "Warning: Failed to reprocess configuration after translation: {}",
                e
            );
        });
    }

    /// Find the menu.toml configuration file
    fn find_config_file(project_root: &Path) -> Result<PathBuf> {
        // Use site structure environment variables
        let site_root = env::var("SITE_ROOT_PATH").unwrap_or_else(|_| "site".to_string());
        let config_path =
            env::var("SITE_CONFIG_PATH").unwrap_or_else(|_| format!("{}/config", site_root));

        let expected_path = project_root
            .join(&config_path)
            .join("dashboard")
            .join("menu.toml");

        if expected_path.exists() {
            return Ok(expected_path);
        }

        // Check if site directory exists at all
        let site_dir = project_root.join(&site_root);
        if !site_dir.exists() {
            return Err(anyhow::anyhow!(
                "Site directory not found: {}\n\
                 Expected site structure:\n\
                 ├── site/\n\
                 │   ├── content/     # Pure content (blog, recipes, pages)\n\
                 │   ├── config/      # App configuration (routes, themes)\n\
                 │   ├── ui/          # UI definitions (menus, footer)\n\
                 │   ├── i18n/        # Internationalization (locales)\n\
                 │   └── assets/      # Static assets\n\n\
                 Environment variables:\n\
                 SITE_ROOT={}\n\
                 SITE_CONFIG_PATH={}",
                site_dir.display(),
                site_root,
                config_path
            ));
        }

        // Check if config directory exists
        let config_dir = project_root.join(&config_path);
        if !config_dir.exists() {
            return Err(anyhow::anyhow!(
                "Site config directory not found: {}\nExpected: {}/config/\nCurrent \
                 SITE_CONFIG_PATH: {}\n\nTo fix this:\n1. Create the config directory: mkdir -p \
                 {}\n2. Or update SITE_CONFIG_PATH environment variable\n3. Dashboard config \
                 should be in: {}",
                config_dir.display(),
                site_root,
                config_path,
                config_dir.display(),
                expected_path.display()
            ));
        }

        // Check if dashboard directory exists
        let dashboard_dir = config_dir.join("dashboard");
        if !dashboard_dir.exists() {
            return Err(anyhow::anyhow!(
                "Dashboard config directory not found: {}\nExpected: {}/config/dashboard/\n\nTo \
                 fix this:\n1. Create dashboard directory: mkdir -p {}\n2. Dashboard menu config \
                 should be: {}",
                dashboard_dir.display(),
                site_root,
                dashboard_dir.display(),
                expected_path.display()
            ));
        }

        // menu.toml doesn't exist - provide helpful error
        Err(anyhow::anyhow!(
            "Dashboard menu configuration not found: {}\n\nExpected site structure:\n{}/\n├── \
             config/\n│   ├── dashboard/\n│   │   └── menu.toml    ← Missing file\n│   ├── \
             routes/\n│   └── themes/\n├── content/\n├── ui/\n├── i18n/\n└── assets/\n\nTo create \
             the menu configuration:\n1. Copy example: cp examples/menu.toml {}\n2. Or create \
             manually with dashboard menu structure\n\nEnvironment: SITE_CONFIG_PATH={}",
            expected_path.display(),
            site_root,
            expected_path.display(),
            config_path
        ))
    }

    /// Process configuration after loading (group actions by category)
    fn process_configuration(&mut self) -> Result<()> {
        // Create a map of actions by category
        let mut actions_by_category: HashMap<String, Vec<MenuAction>> = HashMap::new();

        for action in &self.actions {
            actions_by_category
                .entry(action.category.clone())
                .or_default()
                .push(action.clone());
        }

        // Sort actions within each category by order
        for actions in actions_by_category.values_mut() {
            actions.sort_by_key(|a| a.order);
        }

        // Create categories with their actions
        let mut categories_with_actions = self.categories.clone();
        for category in &mut categories_with_actions {
            if let Some(actions) = actions_by_category.get(&category.id) {
                category.actions = actions.clone();
            }
        }

        // Sort categories by order
        categories_with_actions.sort_by_key(|c| c.order);

        self.categories_with_actions = categories_with_actions;

        Ok(())
    }

    /// Get category by ID
    pub fn get_category(&self, category_id: &str) -> Option<&MenuCategory> {
        self.categories_with_actions
            .iter()
            .find(|c| c.id == category_id)
    }

    /// Get action by category and action ID
    pub fn get_action(&self, category_id: &str, action_id: &str) -> Option<&MenuAction> {
        self.get_category(category_id)?
            .actions
            .iter()
            .find(|a| a.id == action_id)
    }

    /// Get total number of categories
    pub fn category_count(&self) -> usize {
        self.categories_with_actions.len()
    }

    /// Get total number of actions in a category
    pub fn action_count(&self, category_id: &str) -> usize {
        self.get_category(category_id)
            .map(|c| c.actions.len())
            .unwrap_or(0)
    }
}
