//! Declarative configuration for SEA-Forge
//!
//! Supports a `sea-forge.yaml` file for declaring desired state.

use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs;
use std::path::Path;

const CONFIG_FILE: &str = "sea-forge.yaml";

/// Declarative configuration for SEA-Forge
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ForgeConfig {
    /// Version of the config schema
    #[serde(default = "default_version")]
    pub version: String,

    /// Service declarations
    #[serde(default)]
    pub services: HashMap<String, ServiceConfig>,

    /// Environment settings
    #[serde(default)]
    pub environment: EnvironmentConfig,
}

fn default_version() -> String {
    "1".to_string()
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServiceConfig {
    /// Desired state: running, stopped, optional
    #[serde(default = "default_state")]
    pub state: ServiceState,

    /// Health check configuration
    #[serde(default)]
    pub health: Option<HealthCheck>,

    /// Auto-restart on failure
    #[serde(default)]
    pub auto_restart: bool,

    /// Restart delay in seconds
    #[serde(default = "default_restart_delay")]
    pub restart_delay_secs: u64,

    /// Maximum restart attempts (0 = unlimited)
    #[serde(default)]
    pub max_restarts: u32,
}

fn default_state() -> ServiceState {
    ServiceState::Running
}

fn default_restart_delay() -> u64 {
    5
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ServiceState {
    Running,
    Stopped,
    Optional,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthCheck {
    /// HTTP endpoint to check
    pub url: Option<String>,
    /// TCP port to check
    pub port: Option<u16>,
    /// Check interval in seconds
    #[serde(default = "default_interval")]
    pub interval_secs: u64,
    /// Timeout in seconds
    #[serde(default = "default_timeout")]
    pub timeout_secs: u64,
}

fn default_interval() -> u64 {
    30
}

fn default_timeout() -> u64 {
    5
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct EnvironmentConfig {
    /// Auto-setup missing dependencies
    #[serde(default)]
    pub auto_setup: bool,

    /// Watch mode settings
    #[serde(default)]
    pub watch: WatchConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WatchConfig {
    /// Enable watch mode by default
    #[serde(default)]
    pub enabled: bool,

    /// Health check interval in seconds
    #[serde(default = "default_watch_interval")]
    pub interval_secs: u64,
}

impl Default for WatchConfig {
    fn default() -> Self {
        Self {
            enabled: false,
            interval_secs: 30,
        }
    }
}

fn default_watch_interval() -> u64 {
    30
}

impl Default for ForgeConfig {
    fn default() -> Self {
        let mut services = HashMap::new();

        // Default service configurations
        services.insert(
            "librechat".to_string(),
            ServiceConfig {
                state: ServiceState::Running,
                health: Some(HealthCheck {
                    url: Some("http://localhost:3080".to_string()),
                    port: None,
                    interval_secs: 30,
                    timeout_secs: 5,
                }),
                auto_restart: true,
                restart_delay_secs: 5,
                max_restarts: 3,
            },
        );

        services.insert(
            "oxigraph".to_string(),
            ServiceConfig {
                state: ServiceState::Running,
                health: Some(HealthCheck {
                    url: Some("http://localhost:7878".to_string()),
                    port: None,
                    interval_secs: 30,
                    timeout_secs: 5,
                }),
                auto_restart: true,
                restart_delay_secs: 5,
                max_restarts: 3,
            },
        );

        services.insert(
            "ollama".to_string(),
            ServiceConfig {
                state: ServiceState::Optional,
                health: Some(HealthCheck {
                    url: Some("http://localhost:11434/api/tags".to_string()),
                    port: None,
                    interval_secs: 60,
                    timeout_secs: 5,
                }),
                auto_restart: false,
                restart_delay_secs: 10,
                max_restarts: 0,
            },
        );

        Self {
            version: "1".to_string(),
            services,
            environment: EnvironmentConfig::default(),
        }
    }
}

impl ForgeConfig {
    /// Load config from project root, or return defaults
    pub fn load(project_root: &Path) -> Result<Self> {
        let config_path = project_root.join(CONFIG_FILE);
        if config_path.exists() {
            let content = fs::read_to_string(&config_path).context("Failed to read config file")?;
            serde_yaml::from_str(&content).context("Failed to parse config file")
        } else {
            Ok(Self::default())
        }
    }


}
