//! Server configuration

use plasmavmc_types::{FireCrackerConfig, KvmConfig};
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
use std::path::PathBuf;

/// TLS configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TlsConfig {
    /// Path to certificate file (PEM)
    pub cert_file: String,

    /// Path to private key file (PEM)
    pub key_file: String,

    /// Path to CA certificate for client verification (optional, for mTLS)
    pub ca_file: Option<String>,

    /// Require client certificates (mTLS)
    #[serde(default)]
    pub require_client_cert: bool,
}

/// Server configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
    /// Address to listen on
    pub addr: SocketAddr,
    /// HTTP REST API listen address
    #[serde(default = "default_http_addr")]
    pub http_addr: SocketAddr,
    /// Log level
    pub log_level: String,
    /// TLS configuration (optional)
    pub tls: Option<TlsConfig>,
    /// Authentication configuration
    #[serde(default)]
    pub auth: AuthConfig,
    /// Configuration for KVM backend
    #[serde(default)]
    pub kvm: KvmConfig,
    /// Configuration for FireCracker backend
    #[serde(default)]
    pub firecracker: FireCrackerConfig,
    /// Durable/shared state configuration
    #[serde(default)]
    pub storage: StorageRuntimeConfig,
    /// Control-plane and agent heartbeat configuration
    #[serde(default)]
    pub agent: AgentRuntimeConfig,
    /// External service integrations
    #[serde(default)]
    pub integrations: IntegrationConfig,
    /// State watcher and VM watch polling configuration
    #[serde(default)]
    pub watcher: WatcherRuntimeConfig,
    /// Background health monitoring and failover configuration
    #[serde(default)]
    pub health: HealthRuntimeConfig,
    /// Artifact storage and image import/export configuration
    #[serde(default)]
    pub artifacts: ArtifactStoreConfig,
    /// Persistent volume runtime configuration
    #[serde(default)]
    pub volumes: VolumeRuntimeConfig,
    /// Default hypervisor used when requests do not specify one
    #[serde(default)]
    pub default_hypervisor: DefaultHypervisor,
}

fn default_http_addr() -> SocketAddr {
    "127.0.0.1:8084".parse().unwrap()
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "lowercase")]
pub enum StorageBackendKind {
    #[default]
    Flaredb,
    File,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StorageRuntimeConfig {
    #[serde(default)]
    pub backend: StorageBackendKind,
    #[serde(default)]
    pub flaredb_endpoint: Option<String>,
    #[serde(default)]
    pub chainfire_endpoint: Option<String>,
    #[serde(default)]
    pub state_path: Option<PathBuf>,
}

impl Default for StorageRuntimeConfig {
    fn default() -> Self {
        Self {
            backend: StorageBackendKind::default(),
            flaredb_endpoint: None,
            chainfire_endpoint: None,
            state_path: None,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentRuntimeConfig {
    #[serde(default)]
    pub control_plane_addr: Option<String>,
    #[serde(default)]
    pub advertise_endpoint: Option<String>,
    #[serde(default)]
    pub node_id: Option<String>,
    #[serde(default)]
    pub node_name: Option<String>,
    #[serde(default = "default_agent_heartbeat_interval_secs")]
    pub heartbeat_interval_secs: u64,
    #[serde(default = "default_shared_live_migration")]
    pub shared_live_migration: bool,
}

fn default_agent_heartbeat_interval_secs() -> u64 {
    5
}

fn default_shared_live_migration() -> bool {
    true
}

impl Default for AgentRuntimeConfig {
    fn default() -> Self {
        Self {
            control_plane_addr: None,
            advertise_endpoint: None,
            node_id: None,
            node_name: None,
            heartbeat_interval_secs: default_agent_heartbeat_interval_secs(),
            shared_live_migration: default_shared_live_migration(),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct IntegrationConfig {
    #[serde(default)]
    pub prismnet_endpoint: Option<String>,
    #[serde(default)]
    pub creditservice_endpoint: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WatcherRuntimeConfig {
    #[serde(default)]
    pub enabled: bool,
    #[serde(default = "default_state_watcher_poll_interval_ms")]
    pub poll_interval_ms: u64,
    #[serde(default = "default_vm_watch_poll_interval_ms")]
    pub vm_watch_poll_interval_ms: u64,
}

fn default_state_watcher_poll_interval_ms() -> u64 {
    1000
}

fn default_vm_watch_poll_interval_ms() -> u64 {
    500
}

impl Default for WatcherRuntimeConfig {
    fn default() -> Self {
        Self {
            enabled: false,
            poll_interval_ms: default_state_watcher_poll_interval_ms(),
            vm_watch_poll_interval_ms: default_vm_watch_poll_interval_ms(),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthRuntimeConfig {
    #[serde(default)]
    pub vm_monitor_interval_secs: Option<u64>,
    #[serde(default)]
    pub node_monitor_interval_secs: Option<u64>,
    #[serde(default = "default_node_heartbeat_timeout_secs")]
    pub node_heartbeat_timeout_secs: u64,
    #[serde(default)]
    pub auto_restart: bool,
    #[serde(default)]
    pub failover_enabled: bool,
    #[serde(default = "default_failover_min_interval_secs")]
    pub failover_min_interval_secs: u64,
}

fn default_node_heartbeat_timeout_secs() -> u64 {
    60
}

fn default_failover_min_interval_secs() -> u64 {
    60
}

impl Default for HealthRuntimeConfig {
    fn default() -> Self {
        Self {
            vm_monitor_interval_secs: None,
            node_monitor_interval_secs: None,
            node_heartbeat_timeout_secs: default_node_heartbeat_timeout_secs(),
            auto_restart: false,
            failover_enabled: false,
            failover_min_interval_secs: default_failover_min_interval_secs(),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArtifactStoreConfig {
    #[serde(default)]
    pub lightningstor_endpoint: Option<String>,
    #[serde(default = "default_image_cache_dir")]
    pub image_cache_dir: PathBuf,
    #[serde(default = "default_image_bucket")]
    pub image_bucket: String,
    #[serde(default = "default_multipart_upload_concurrency")]
    pub multipart_upload_concurrency: usize,
    #[serde(default = "default_multipart_upload_part_size")]
    pub multipart_upload_part_size: usize,
    #[serde(default = "default_raw_image_convert_parallelism")]
    pub raw_image_convert_parallelism: usize,
    #[serde(default = "default_image_import_connect_timeout_secs")]
    pub image_import_connect_timeout_secs: u64,
    #[serde(default = "default_image_import_timeout_secs")]
    pub image_import_timeout_secs: u64,
    #[serde(default = "default_max_image_import_size_bytes")]
    pub max_image_import_size_bytes: u64,
    #[serde(default)]
    pub allowed_https_hosts: Vec<String>,
    #[serde(default)]
    pub qemu_img_path: Option<PathBuf>,
}

fn default_image_cache_dir() -> PathBuf {
    PathBuf::from("/var/lib/plasmavmc/images")
}

fn default_image_bucket() -> String {
    "plasmavmc-images".to_string()
}

fn default_multipart_upload_concurrency() -> usize {
    4
}

fn default_multipart_upload_part_size() -> usize {
    32 * 1024 * 1024
}

fn default_raw_image_convert_parallelism() -> usize {
    8
}

fn default_image_import_connect_timeout_secs() -> u64 {
    5
}

fn default_image_import_timeout_secs() -> u64 {
    60 * 60
}

fn default_max_image_import_size_bytes() -> u64 {
    64 * 1024 * 1024 * 1024
}

impl Default for ArtifactStoreConfig {
    fn default() -> Self {
        Self {
            lightningstor_endpoint: None,
            image_cache_dir: default_image_cache_dir(),
            image_bucket: default_image_bucket(),
            multipart_upload_concurrency: default_multipart_upload_concurrency(),
            multipart_upload_part_size: default_multipart_upload_part_size(),
            raw_image_convert_parallelism: default_raw_image_convert_parallelism(),
            image_import_connect_timeout_secs: default_image_import_connect_timeout_secs(),
            image_import_timeout_secs: default_image_import_timeout_secs(),
            max_image_import_size_bytes: default_max_image_import_size_bytes(),
            allowed_https_hosts: Vec::new(),
            qemu_img_path: None,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct CoronaFsConfig {
    #[serde(default)]
    pub controller_endpoint: Option<String>,
    #[serde(default)]
    pub node_endpoint: Option<String>,
    #[serde(default)]
    pub endpoint: Option<String>,
    #[serde(default)]
    pub node_local_attach: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CephConfig {
    #[serde(default)]
    pub monitors: Vec<String>,
    #[serde(default = "default_ceph_cluster_id")]
    pub cluster_id: String,
    #[serde(default = "default_ceph_user")]
    pub user: String,
    #[serde(default)]
    pub secret: Option<String>,
}

fn default_ceph_cluster_id() -> String {
    "default".to_string()
}

fn default_ceph_user() -> String {
    "admin".to_string()
}

impl Default for CephConfig {
    fn default() -> Self {
        Self {
            monitors: Vec::new(),
            cluster_id: default_ceph_cluster_id(),
            user: default_ceph_user(),
            secret: None,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VolumeRuntimeConfig {
    #[serde(default = "default_managed_volume_root")]
    pub managed_volume_root: PathBuf,
    #[serde(default)]
    pub ceph: CephConfig,
    #[serde(default)]
    pub coronafs: CoronaFsConfig,
    #[serde(default)]
    pub qemu_img_path: Option<PathBuf>,
}

fn default_managed_volume_root() -> PathBuf {
    PathBuf::from("/var/lib/plasmavmc/managed-volumes")
}

impl Default for VolumeRuntimeConfig {
    fn default() -> Self {
        Self {
            managed_volume_root: default_managed_volume_root(),
            ceph: CephConfig::default(),
            coronafs: CoronaFsConfig::default(),
            qemu_img_path: None,
        }
    }
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "lowercase")]
pub enum DefaultHypervisor {
    #[default]
    Kvm,
    Firecracker,
    Mvisor,
}

/// Authentication configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthConfig {
    /// IAM server endpoint
    #[serde(default = "default_iam_server_addr")]
    pub iam_server_addr: String,
}

fn default_iam_server_addr() -> String {
    "127.0.0.1:50051".to_string()
}

impl Default for AuthConfig {
    fn default() -> Self {
        Self {
            iam_server_addr: default_iam_server_addr(),
        }
    }
}

impl Default for ServerConfig {
    fn default() -> Self {
        Self {
            addr: "0.0.0.0:8080".parse().unwrap(),
            http_addr: default_http_addr(),
            log_level: "info".to_string(),
            tls: None,
            auth: AuthConfig::default(),
            kvm: KvmConfig::default(),
            firecracker: FireCrackerConfig::default(),
            storage: StorageRuntimeConfig::default(),
            agent: AgentRuntimeConfig::default(),
            integrations: IntegrationConfig::default(),
            watcher: WatcherRuntimeConfig::default(),
            health: HealthRuntimeConfig::default(),
            artifacts: ArtifactStoreConfig::default(),
            volumes: VolumeRuntimeConfig::default(),
            default_hypervisor: DefaultHypervisor::default(),
        }
    }
}
