use std::env;

#[derive(Debug, Clone)]
pub struct Config {
  pub stripe_secret_key: String,
  pub stripe_price_id: String,
  pub signing_key_hex: String,
  pub database_url: String,
  pub release_dir: String,
  pub static_dir: String,
  pub port: u16,
  pub app_url: String,
}

impl Config {
  pub fn from_env() -> Self {
    load_dotenv();

    Self {
      stripe_secret_key: env::var("STRIPE_SECRET_KEY")
        .unwrap_or_else(|_| "sk_test_placeholder".to_string()),
      stripe_price_id: env::var("STRIPE_PRICE_ID").unwrap_or_default(),
      signing_key_hex: env::var("SIGNING_KEY_HEX").unwrap_or_else(|_| "0".repeat(64)),
      database_url: env::var("DATABASE_URL").unwrap_or_else(|_| "sqlite::memory:".to_string()),
      release_dir: env::var("RELEASE_DIR").unwrap_or_else(|_| "./releases".to_string()),
      static_dir: env::var("STATIC_DIR")
        .unwrap_or_else(|_| "./static".to_string()),
      port: env::var("PORT")
        .unwrap_or_else(|_| "3000".to_string())
        .parse()
        .unwrap_or(3000),
      app_url: env::var("APP_URL").unwrap_or_else(|_| "http://localhost:3000".to_string()),
    }
  }
}

fn load_dotenv() {
  if let Ok(cwd) = env::current_dir() {
    let cwd_env = cwd.join(".env");
    if cwd_env.exists() {
      dotenvy::from_path(&cwd_env).ok();
      return;
    }
    let cwd_server_env = cwd.join("server").join(".env");
    if cwd_server_env.exists() {
      dotenvy::from_path(&cwd_server_env).ok();
      return;
    }
  }

  if let Ok(exe) = env::current_exe() {
    if let Some(exe_dir) = exe.parent() {
      let mut dir = exe_dir.to_path_buf();

      loop {
        let env_path = dir.join(".env");

        if env_path.exists() {
          dotenvy::from_path(&env_path).ok();
          return;
        }

        if !dir.pop() {
          break;
        }
      }
    }
  }

  dotenvy::dotenv().ok();
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn test_config_defaults() {
    let config = Config {
      stripe_secret_key: "sk_test_placeholder".to_string(),
      stripe_price_id: String::new(),
      signing_key_hex: "0".repeat(64),
      database_url: "sqlite::memory:".to_string(),
      release_dir: "./releases".to_string(),
      static_dir: "./static".to_string(),
      port: 3000,
      app_url: "http://localhost:3000".to_string(),
    };

    assert_eq!(config.stripe_secret_key, "sk_test_placeholder");
    assert!(config.stripe_price_id.is_empty());
    assert_eq!(config.signing_key_hex, "0".repeat(64));
    assert_eq!(config.database_url, "sqlite::memory:");
    assert_eq!(config.release_dir, "./releases");
    assert_eq!(config.static_dir, "./static");
    assert_eq!(config.port, 3000);
    assert_eq!(config.app_url, "http://localhost:3000");
  }

  #[test]
  fn test_config_custom_values() {
    let config = Config {
      stripe_secret_key: "sk_test_abc123".to_string(),
      stripe_price_id: "price_123".to_string(),
      signing_key_hex: "a".repeat(64),
      database_url: "sqlite:./test.db".to_string(),
      release_dir: "/data/releases".to_string(),
      static_dir: "/app/server/static".to_string(),
      port: 8080,
      app_url: "https://cleancopy.app".to_string(),
    };

    assert_eq!(config.stripe_secret_key, "sk_test_abc123");
    assert_eq!(config.stripe_price_id, "price_123");
    assert_eq!(config.signing_key_hex, "a".repeat(64));
    assert_eq!(config.database_url, "sqlite:./test.db");
    assert_eq!(config.release_dir, "/data/releases");
    assert_eq!(config.static_dir, "/app/server/static");
    assert_eq!(config.port, 8080);
    assert_eq!(config.app_url, "https://cleancopy.app");
  }

  #[test]
  fn test_port_parse_invalid_falls_back_to_3000() {
    let port: u16 = "not_a_number".parse().unwrap_or(3000);
    assert_eq!(port, 3000);
  }
}
