use anyhow::{Context, Result};
use chrono::{self};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    // Economic calendar start (usually the earliest available on finanzen.net)
    pub economic_start_date: String,     // e.g. "2007-02-13"
    // Corporate earnings & price history start
    pub corporate_start_date: String,    // e.g. "2000-01-01" or "2010-01-01"
    // How far into the future we scrape economic events
    pub economic_lookahead_months: u32,  // default: 3
    /// Maximum number of parallel scraping tasks (default: 10).
    /// This limits concurrency to protect system load and prevent website spamming.
    #[serde(default = "default_max_parallel")]
    pub max_parallel_tasks: usize,
}

fn default_max_parallel() -> usize {
    10
}

impl Default for Config {
    fn default() -> Self {
        Self {
            economic_start_date: "2007-02-13".to_string(),
            corporate_start_date: "2010-01-01".to_string(),
            economic_lookahead_months: 3,
            max_parallel_tasks: default_max_parallel(),
        }
    }
}

impl Config {
    /// Loads the configuration from environment variables using dotenvy.
    ///
    /// This function loads a `.env` file if present (via `dotenvy::dotenv()`),
    /// then retrieves each configuration value from environment variables.
    /// If a variable is missing, it falls back to the default value.
    /// Variable names are uppercase with underscores (e.g., ECONOMIC_START_DATE).
    ///
    /// # Returns
    /// The loaded Config on success.
    ///
    /// # Errors
    /// Returns an error if parsing fails (e.g., invalid integer for lookahead months).
    pub fn load() -> Result<Self> {
        // Load .env file if it exists; ignore if not found (dotenvy::dotenv returns Ok if no file)
        let _ = dotenvy::dotenv().context("Failed to load .env file (optional)")?;

        let economic_start_date = dotenvy::var("ECONOMIC_START_DATE")
            .unwrap_or_else(|_| "2007-02-13".to_string());

        let corporate_start_date = dotenvy::var("CORPORATE_START_DATE")
            .unwrap_or_else(|_| "2010-01-01".to_string());

        let economic_lookahead_months: u32 = dotenvy::var("ECONOMIC_LOOKAHEAD_MONTHS")
            .unwrap_or_else(|_| "3".to_string())
            .parse()
            .context("Failed to parse ECONOMIC_LOOKAHEAD_MONTHS as u32")?;

        let max_parallel_tasks: usize = dotenvy::var("MAX_PARALLEL_TASKS")
            .unwrap_or_else(|_| "10".to_string())
            .parse()
            .context("Failed to parse MAX_PARALLEL_TASKS as usize")?;

        Ok(Self {
            economic_start_date,
            corporate_start_date,
            economic_lookahead_months,
            max_parallel_tasks,
        })
    }

    pub fn target_end_date(&self) -> String {
        let now = chrono::Local::now().naive_local().date();
        let future = now + chrono::Duration::days(30 * self.economic_lookahead_months as i64);
        future.format("%Y-%m-%d").to_string()
    }
}