use anyhow::{Context, Result};
use std::env;

#[derive(Debug, Clone)]
pub enum AccessType {
    Local,
    Smb,
    Synology,
}

#[derive(Debug, Clone)]
pub struct AccessConfig {
    pub access_type: AccessType,
    pub local_path: Option<String>,
    pub smb_url: Option<String>,
    pub smb_user: Option<String>,
    pub smb_pass: Option<String>,
    pub synology_path: Option<String>,
}

impl AccessConfig {
    fn from_env(prefix: &str) -> Result<Self> {
        let local_path = env::var(format!("{}_LOCAL_PATH", prefix)).ok();
        let smb_url = env::var(format!("{}_SMB_URL", prefix)).ok();
        let synology_path = env::var(format!("{}_SYNOLOGY_PATH", prefix)).ok();

        let access_type = if local_path.is_some() && smb_url.is_none() && synology_path.is_none() {
            AccessType::Local
        } else if smb_url.is_some() && local_path.is_none() && synology_path.is_none() {
            AccessType::Smb
        } else if synology_path.is_some() && local_path.is_none() && smb_url.is_none() {
            AccessType::Synology
        } else {
            anyhow::bail!(
                "Exactly one of {}_LOCAL_PATH, {}_SMB_URL, {}_SYNOLOGY_PATH must be set",
                prefix,
                prefix,
                prefix
            );
        };

        Ok(AccessConfig {
            access_type,
            local_path,
            smb_url,
            smb_user: env::var(format!("{}_SMB_USER", prefix)).ok(),
            smb_pass: env::var(format!("{}_SMB_PASS", prefix)).ok(),
            synology_path,
        })
    }
}

#[derive(Debug, Clone)]
pub struct Config {
    // Synology
    pub nas_fqdn: String,
    pub nas_user: String,
    pub nas_pass: String,
    pub nas_file: String,
    // Nexrender
    pub nexrender_api_url: String,
    pub output_folder: String,
    // Templates
    pub template_double_src: String,
    pub template_single_src: String,
    pub template_composition: String,
    pub template_output_module: String,
    pub template_output_ext: String,
    // Web server
    pub web_port: u16,
    // Source (where rendered videos appear)
    pub source: AccessConfig,
    // Destination (where to move approved videos)
    pub destination: AccessConfig,
}

impl Config {
    pub fn from_env() -> Result<Self> {
        Ok(Self {
            nas_fqdn: env::var("NAS_FQDN").context("NAS_FQDN not set")?,
            nas_user: env::var("NAS_USER").context("NAS_USER not set")?,
            nas_pass: env::var("NAS_PASS").context("NAS_PASS not set")?,
            nas_file: env::var("NAS_FILE").context("NAS_FILE not set")?,
            nexrender_api_url: env::var("NEXRENDER_API_URL")
                .context("NEXRENDER_API_URL not set")?,
            output_folder: env::var("OUTPUT_FOLDER").context("OUTPUT_FOLDER not set")?,
            template_double_src: env::var("TEMPLATE_DOUBLE_SRC")
                .context("TEMPLATE_DOUBLE_SRC not set")?,
            template_single_src: env::var("TEMPLATE_SINGLE_SRC")
                .context("TEMPLATE_SINGLE_SRC not set")?,
            template_composition: env::var("TEMPLATE_COMPOSITION")
                .context("TEMPLATE_COMPOSITION not set")?,
            template_output_module: env::var("TEMPLATE_OUTPUT_MODULE")
                .context("TEMPLATE_OUTPUT_MODULE not set")?,
            template_output_ext: env::var("TEMPLATE_OUTPUT_EXT")
                .context("TEMPLATE_OUTPUT_EXT not set")?,
            web_port: env::var("WEB_PORT")
                .unwrap_or_else(|_| "3000".to_string())
                .parse()
                .context("Invalid WEB_PORT")?,
            source: AccessConfig::from_env("SOURCE")?,
            destination: AccessConfig::from_env("DESTINATION")?,
        })
    }
}
