//! Configuration management for Rustelo framework

use std::path::{Path, PathBuf};

use serde::{Deserialize, Serialize};

use crate::error::{Result, RusteloError};

/// Base configuration structure for Rustelo applications
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RusteloConfig {
    /// Application name
    pub app_name: String,

    /// Environment (dev, prod, test)
    pub environment: String,

    /// Base paths for asset resolution
    pub paths: PathConfig,

    /// Framework-specific settings
    pub framework: FrameworkConfig,
}

/// Path configuration for asset resolution
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PathConfig {
    /// Root directory for the implementation
    pub root: PathBuf,

    /// Framework assets directory
    pub framework_assets: PathBuf,

    /// Implementation assets directory
    pub local_assets: PathBuf,

    /// Output directory for built assets
    pub output: PathBuf,
}

/// Framework-specific configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FrameworkConfig {
    /// Framework version
    pub version: String,

    /// Enabled features
    pub features: Vec<String>,

    /// Asset resolution strategy
    pub asset_resolution: AssetResolution,
}

/// Asset resolution strategy configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AssetResolution {
    /// Whether to use fallback resolution
    pub enable_fallback: bool,

    /// Priority order for asset resolution
    pub priority: Vec<AssetSource>,
}

/// Source for asset resolution
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum AssetSource {
    Local,
    Framework,
    Generated,
}

impl Default for RusteloConfig {
    fn default() -> Self {
        Self {
            app_name: "rustelo-app".to_string(),
            environment: "dev".to_string(),
            paths: PathConfig::default(),
            framework: FrameworkConfig::default(),
        }
    }
}

impl Default for PathConfig {
    fn default() -> Self {
        Self {
            root: PathBuf::from("."),
            framework_assets: PathBuf::from("../rustelo/assets"),
            local_assets: PathBuf::from("assets"),
            output: PathBuf::from("target/assets"),
        }
    }
}

impl Default for FrameworkConfig {
    fn default() -> Self {
        Self {
            version: crate::VERSION.to_string(),
            features: vec!["web".to_string()],
            asset_resolution: AssetResolution::default(),
        }
    }
}

impl Default for AssetResolution {
    fn default() -> Self {
        Self {
            enable_fallback: true,
            priority: vec![
                AssetSource::Local,
                AssetSource::Framework,
                AssetSource::Generated,
            ],
        }
    }
}

impl RusteloConfig {
    /// Load configuration from a TOML file
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
        let content = std::fs::read_to_string(path).map_err(RusteloError::Io)?;

        let config: Self = toml::from_str(&content)
            .map_err(|e| RusteloError::config(format!("Failed to parse config: {}", e)))?;

        Ok(config)
    }

    /// Save configuration to a TOML file
    pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        let content = toml::to_string_pretty(self)
            .map_err(|e| RusteloError::config(format!("Failed to serialize config: {}", e)))?;

        std::fs::write(path, content).map_err(RusteloError::Io)?;

        Ok(())
    }

    /// Load configuration from default location or create default if not found
    pub fn load() -> Result<Self> {
        Self::from_file("rustelo.toml").or_else(|_| {
            tracing::warn!("Configuration file not found, using defaults");
            Ok(Self::default())
        })
    }
}
