use serde::Deserialize;
use std::path::Path;

const DEFAULT_CONFIG_PATH: &str = "config.toml";
const DEFAULT_SECRET_CONFIG_PATH: &str = "secret-config.toml";

#[derive(Debug, Clone, Deserialize)]
struct PublicConfig {
    pub postgres_host: String,
    pub pg_database: String,
    pub postgres_user: String,
    pub file_storage: String,
    pub dedicated_ai_server_address: String,
    pub dedicated_ai_server_port: u16,
}

#[derive(Debug, Clone, Deserialize)]
struct SecretConfig {
    pub dedicated_ai_server_secret: String,
}

#[derive(Debug, Clone, Deserialize)]
pub struct GeneralServiceConfig {
    pub postgres_host: String,
    pub pg_database: String,
    pub postgres_user: String,
    pub file_storage: String,
    pub dedicated_ai_server_address: String,
    pub dedicated_ai_server_port: u16,
    pub dedicated_ai_server_secret: String,
}

pub type ConfigResult<T> = Result<T, Box<dyn std::error::Error>>;

pub fn load_config(config_path: impl AsRef<Path>, secret_config_path: impl AsRef<Path>) -> ConfigResult<GeneralServiceConfig> {
    let raw_config = std::fs::read_to_string(config_path.as_ref())?;
    let public_config: PublicConfig = toml::from_str(&raw_config)?;
    let raw_secret = std::fs::read_to_string(secret_config_path.as_ref())?;
    let secret_config: SecretConfig = toml::from_str(&raw_secret)?;

    let config = GeneralServiceConfig {
        postgres_host: public_config.postgres_host,
        pg_database: public_config.pg_database,
        postgres_user: public_config.postgres_user,
        file_storage: public_config.file_storage,
        dedicated_ai_server_address: public_config.dedicated_ai_server_address,
        dedicated_ai_server_port: public_config.dedicated_ai_server_port,
        dedicated_ai_server_secret: secret_config.dedicated_ai_server_secret,
    };

    if config.pg_database.trim().is_empty() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            "config database is empty",
        )
        .into());
    }

    if config.postgres_user.trim().is_empty() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            "config user is empty",
        )
        .into());
    }

    if config.file_storage.trim().is_empty() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            "config file_storage is empty",
        )
        .into());
    }

    if config.dedicated_ai_server_secret.trim().is_empty() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            "config dedicated_ai_server_secret is empty",
        )
        .into());
    }

    Ok(config)
}

pub fn load_config_default() -> ConfigResult<GeneralServiceConfig> {
    load_config(DEFAULT_CONFIG_PATH, DEFAULT_SECRET_CONFIG_PATH)
}
