//! Centralized mi6 directory management.
//!
//! This module handles all path resolution for the mi6 data directory.
//! The directory structure is:
//!
//! ```text
//! ~/.mi6/                    # or MI6_DIR_PATH
//! ├── config.toml           # Unified configuration (core + TUI)
//! ├── mi6.db                # SQLite database
//! └── themes/               # User themes directory
//!     └── example_theme.toml  # Example theme (not loaded as actual theme)
//! ```

use crate::model::error::ConfigError;
use std::fs;
use std::path::PathBuf;

/// Environment variable to override the mi6 directory path.
const MI6_DIR_PATH_ENV: &str = "MI6_DIR_PATH";

/// Example theme filename (excluded from theme loading).
pub const EXAMPLE_THEME_FILENAME: &str = "example_theme.toml";

/// Example theme name without extension (for theme filtering).
pub const EXAMPLE_THEME_NAME: &str = "example_theme";

/// Get the mi6 directory path.
///
/// Resolution order:
/// 1. `MI6_DIR_PATH` environment variable (if set)
/// 2. Default: `~/.mi6`
///
/// This function does not create the directory or initialize it.
/// Use [`ensure_initialized`] to create and populate the directory.
pub fn mi6_dir() -> Result<PathBuf, ConfigError> {
    if let Ok(path) = std::env::var(MI6_DIR_PATH_ENV) {
        return Ok(PathBuf::from(path));
    }

    let home = dirs::home_dir().ok_or(ConfigError::NoHomeDir)?;
    Ok(home.join(".mi6"))
}

/// Get the database path.
///
/// Returns `<mi6_dir>/mi6.db`.
pub fn db_path() -> Result<PathBuf, ConfigError> {
    Ok(mi6_dir()?.join("mi6.db"))
}

/// Get the core config file path (TOML format).
///
/// Returns `<mi6_dir>/config.toml`.
pub fn core_config_path() -> Result<PathBuf, ConfigError> {
    Ok(mi6_dir()?.join("config.toml"))
}

/// Get the themes directory path.
///
/// Returns `<mi6_dir>/themes`.
pub fn themes_dir() -> Result<PathBuf, ConfigError> {
    Ok(mi6_dir()?.join("themes"))
}

/// Ensure the mi6 directory is initialized.
///
/// Creates the directory structure and populates initial files if they don't exist:
/// - `<mi6_dir>/themes/example_theme.toml`
///
/// Returns the mi6 directory path.
pub fn ensure_initialized() -> Result<PathBuf, ConfigError> {
    let dir = mi6_dir()?;

    // Create the main directory
    fs::create_dir_all(&dir)?;

    // Create themes directory
    let themes = dir.join("themes");
    fs::create_dir_all(&themes)?;

    // Create example theme if it doesn't exist
    let example_theme = themes.join(EXAMPLE_THEME_FILENAME);
    if !example_theme.exists() {
        fs::write(&example_theme, EXAMPLE_THEME_CONTENT)?;
    }

    Ok(dir)
}

/// Content for the example theme file.
const EXAMPLE_THEME_CONTENT: &str = r##"# Example mi6 Theme
#
# This file demonstrates how to create custom themes for mi6.
# To create your own theme:
#   1. Copy this file to a new name (e.g., mytheme.toml)
#   2. Customize the colors below
#   3. Select your theme in mi6 using 't' to cycle themes
#
# Note: Files named "example_theme.toml" are ignored by the theme loader.
#
# Color values can be:
#   - Named colors: "red", "green", "blue", "yellow", "cyan", "magenta",
#                   "white", "black", "gray", "dark_gray"
#   - Hex colors: "#ff5500", "#abc"
#   - RGB: { r = 255, g = 100, b = 50 }
#   - Variable references: "$accent" (refers to palette.accent)
#
# Style values can be:
#   - A color string: "cyan" or "$accent"
#   - A full style: { fg = "$accent", bg = "$bg", modifiers = ["bold"] }

[meta]
# Theme spec version (current: 1). Optional but recommended.
version = 1
name = "my_custom_theme"
show_borders = true

# Color palette - define colors once, reference with $name
# This eliminates duplication and makes themes easier to customize.
# Change a color in the palette and it updates everywhere it's referenced.
[palette]
bg = "#282a36"
fg = "#f8f8f2"
accent = "#bd93f9"
muted = "#6272a4"
danger = "#ff5555"
success = "#50fa7b"
warning = "#f1fa8c"
orange = "#ffb86c"
info = "#8be9fd"

[core]
border = "$accent"

[text]
primary = "$fg"
secondary = "$muted"
muted = "$muted"
accent = "$accent"

[interactive]
highlight = { bg = "#44475a" }
cursor = { fg = "$bg", bg = "$fg" }
shortcut = "$warning"
help_label = "$fg"
header = "$warning"
sessions = "$success"

[semantic]
danger = "$danger"
danger_border = "$danger"
success = "$success"
warning = "$warning"
info = "$info"

[components.scrollbar]
thumb = "$accent"
track = "$muted"

[components.checkbox]
bracket = "$muted"
check = "$success"

[fields]
column_default = "$fg"
tokens = "$accent"
in = "$accent"
out = "$accent"
cache = "$info"
cachew = "$info"
context = "$info"
cost = "$success"
pr = "$accent"
issue = "$accent"

# Dynamic coloring for CPU percentage
# Thresholds define the boundaries: [low, medium, high]
# Colors apply to ranges: <low, low-medium, medium-high, >high
# You can use palette variables here too!
[dynamic.cpu]
type = "range"
thresholds = [25.0, 50.0, 75.0]
styles = ["$success", "$warning", "$orange", "$danger"]

# Dynamic coloring for memory usage (in bytes)
# 500MB, 1GB, 2GB thresholds
[dynamic.mem]
type = "range"
thresholds = [524288000, 1073741824, 2147483648]
styles = ["$fg", "$warning", "$orange", "$danger"]

# Dynamic coloring for session status
[dynamic.status]
type = "map"
default = "$info"
[dynamic.status.values]
idle = "$success"
busy = "$warning"
wait = "$info"
done = "$muted"
alive = "$success"
dead = "$danger"
unknown = "$info"
"##;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_mi6_dir_default() {
        // When MI6_DIR_PATH is not set, should return ~/.mi6
        // Note: This test may be affected by env var set elsewhere
        let dir = mi6_dir();
        assert!(dir.is_ok());
        let dir = dir.unwrap();
        assert!(dir.ends_with(".mi6") || std::env::var(MI6_DIR_PATH_ENV).is_ok());
    }

    #[test]
    fn test_db_path() {
        let path = db_path();
        assert!(path.is_ok());
        let path = path.unwrap();
        assert!(path.ends_with("mi6.db"));
    }

    #[test]
    fn test_themes_dir() {
        let path = themes_dir();
        assert!(path.is_ok());
        let path = path.unwrap();
        assert!(path.ends_with("themes"));
    }

    #[test]
    fn test_core_config_path() {
        let path = core_config_path();
        assert!(path.is_ok());
        let path = path.unwrap();
        assert!(path.ends_with("config.toml"));
    }
}
