//! Server configuration

use lightningstor_distributed::DistributedConfig;
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;

/// 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,
}

/// Metadata storage backend
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum MetadataBackend {
    /// FlareDB distributed metadata database
    FlareDb,
    /// PostgreSQL metadata database
    Postgres,
    /// SQLite metadata database (single-node only)
    Sqlite,
}

impl Default for MetadataBackend {
    fn default() -> Self {
        Self::FlareDb
    }
}

/// Object data storage backend
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum ObjectStorageBackend {
    /// Store object data directly on the local filesystem.
    #[default]
    LocalFs,
    /// Coordinate object data across LightningStor storage nodes.
    Distributed,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct S3AuthConfig {
    #[serde(default = "default_s3_auth_enabled")]
    pub enabled: bool,

    #[serde(default = "default_s3_aws_region")]
    pub aws_region: String,

    #[serde(default = "default_s3_iam_cache_ttl_secs")]
    pub iam_cache_ttl_secs: u64,

    #[serde(default = "default_s3_default_org_id")]
    pub default_org_id: Option<String>,

    #[serde(default = "default_s3_default_project_id")]
    pub default_project_id: Option<String>,

    #[serde(default = "default_s3_max_auth_body_bytes")]
    pub max_auth_body_bytes: usize,
}

impl Default for S3AuthConfig {
    fn default() -> Self {
        Self {
            enabled: default_s3_auth_enabled(),
            aws_region: default_s3_aws_region(),
            iam_cache_ttl_secs: default_s3_iam_cache_ttl_secs(),
            default_org_id: default_s3_default_org_id(),
            default_project_id: default_s3_default_project_id(),
            max_auth_body_bytes: default_s3_max_auth_body_bytes(),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct S3PerformanceConfig {
    #[serde(default = "default_s3_streaming_put_threshold_bytes")]
    pub streaming_put_threshold_bytes: usize,

    #[serde(default = "default_s3_inline_put_max_bytes")]
    pub inline_put_max_bytes: usize,

    #[serde(default = "default_s3_multipart_put_concurrency")]
    pub multipart_put_concurrency: usize,

    #[serde(default = "default_s3_multipart_fetch_concurrency")]
    pub multipart_fetch_concurrency: usize,
}

impl Default for S3PerformanceConfig {
    fn default() -> Self {
        Self {
            streaming_put_threshold_bytes: default_s3_streaming_put_threshold_bytes(),
            inline_put_max_bytes: default_s3_inline_put_max_bytes(),
            multipart_put_concurrency: default_s3_multipart_put_concurrency(),
            multipart_fetch_concurrency: default_s3_multipart_fetch_concurrency(),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct S3Config {
    #[serde(default)]
    pub auth: S3AuthConfig,

    #[serde(default)]
    pub performance: S3PerformanceConfig,
}

/// Server configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
    /// gRPC address to listen on
    pub grpc_addr: SocketAddr,

    /// S3 HTTP API address to listen on
    pub s3_addr: SocketAddr,

    /// Log level
    pub log_level: String,

    /// ChainFire endpoint for cluster coordination only
    pub chainfire_endpoint: Option<String>,

    /// FlareDB endpoint for metadata and tenant data storage
    pub flaredb_endpoint: Option<String>,

    /// Metadata backend selection (flaredb, postgres, sqlite)
    #[serde(default)]
    pub metadata_backend: MetadataBackend,

    /// SQL database URL for metadata when backend is postgres or sqlite
    pub metadata_database_url: Option<String>,

    /// Allow single-node mode (required for SQLite)
    #[serde(default)]
    pub single_node: bool,

    /// Data directory for object storage
    pub data_dir: String,

    /// Object data storage backend selection
    #[serde(default)]
    pub object_storage_backend: ObjectStorageBackend,

    /// Distributed object storage settings (used when backend=distributed)
    #[serde(default)]
    pub distributed: DistributedConfig,

    /// Whether local filesystem writes should be flushed before success is returned.
    #[serde(default)]
    pub sync_on_write: bool,

    /// TLS configuration (optional)
    pub tls: Option<TlsConfig>,

    /// Authentication configuration
    #[serde(default)]
    pub auth: AuthConfig,

    /// S3 API runtime settings
    #[serde(default)]
    pub s3: S3Config,
}

/// 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()
}

fn default_s3_auth_enabled() -> bool {
    true
}

fn default_s3_aws_region() -> String {
    "us-east-1".to_string()
}

fn default_s3_iam_cache_ttl_secs() -> u64 {
    30
}

fn default_s3_default_org_id() -> Option<String> {
    Some("default".to_string())
}

fn default_s3_default_project_id() -> Option<String> {
    Some("default".to_string())
}

fn default_s3_max_auth_body_bytes() -> usize {
    1024 * 1024 * 1024
}

fn default_s3_streaming_put_threshold_bytes() -> usize {
    16 * 1024 * 1024
}

fn default_s3_inline_put_max_bytes() -> usize {
    128 * 1024 * 1024
}

fn default_s3_multipart_put_concurrency() -> usize {
    4
}

fn default_s3_multipart_fetch_concurrency() -> usize {
    4
}

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

impl Default for ServerConfig {
    fn default() -> Self {
        Self {
            grpc_addr: "0.0.0.0:9000".parse().unwrap(),
            s3_addr: "0.0.0.0:9001".parse().unwrap(),
            log_level: "info".to_string(),
            chainfire_endpoint: None,
            flaredb_endpoint: None,
            metadata_backend: MetadataBackend::FlareDb,
            metadata_database_url: None,
            single_node: false,
            data_dir: "/var/lib/lightningstor/data".to_string(),
            object_storage_backend: ObjectStorageBackend::LocalFs,
            distributed: DistributedConfig::default(),
            sync_on_write: false,
            tls: None,
            auth: AuthConfig::default(),
            s3: S3Config::default(),
        }
    }
}
