// src/economic/update.rs
use super::{scraper::*, storage::*, helpers::*, types::*};
use crate::{config::Config, scraper::webdriver::ScrapeTask};
use crate::scraper::webdriver::ChromeDriverPool;
use chrono::{Local};
use std::sync::Arc;

/// Runs the full update for economic data, using the provided ChromeDriver pool.
///
/// # Arguments
/// * `config` - The application configuration.
/// * `pool` - Shared pool of ChromeDriver instances for scraping.
///
/// # Errors
/// Returns an error if scraping, loading, or saving fails.
pub async fn run_full_update(config: &Config, pool: &Arc<ChromeDriverPool>) -> anyhow::Result<()> {
    let today_str = chrono::Local::now().date_naive().format("%Y-%m-%d").to_string();
    let end_date = config.target_end_date();

    let chunks = scan_existing_chunks().await?;
    let mut events = load_existing_events(&chunks).await?;
    println!("Loaded {} events from {} chunks", events.len(), chunks.len());

    let start_date = if events.is_empty() {
        config.economic_start_date.clone()
    } else if events.values().any(|e| e.date >= today_str) {
        today_str.clone()
    } else {
        events.values()
            .filter_map(|e| chrono::NaiveDate::parse_from_str(&e.date, "%Y-%m-%d").ok())
            .max()
            .and_then(|d| d.succ_opt())
            .map(|d| d.format("%Y-%m-%d").to_string())
            .unwrap_or(today_str.clone())
    };

    println!("Scraping economic events: {} → {}", start_date, end_date);

    // Pass the pool to the scraping function
    let new_events_all = scrape_all_economic_events(&start_date, &end_date, pool).await?;

    // Process all at once or in batches
    let result = process_batch(&new_events_all, &mut events, &today_str);
    let total_changes = result.changes.len();
    save_changes(&result.changes).await?;

    save_optimized_chunks(events).await?;
    println!("Economic update complete — {} changes detected", total_changes);
    Ok(())
}

/// Scrapes all economic events from start to end date using a dedicated ScrapeTask with the provided pool.
///
/// This function creates a ScrapeTask to navigate to the Finanzen.net page, prepare it,
/// and then loop through date ranges to extract events.
///
/// # Arguments
/// * `start` - Start date in YYYY-MM-DD.
/// * `end` - End date in YYYY-MM-DD.
/// * `pool` - Shared pool of ChromeDriver instances.
///
/// # Returns
/// A vector of all extracted EconomicEvent structs.
///
/// # Errors
/// Returns an error if task execution fails or extraction issues occur.
pub async fn scrape_all_economic_events(start: &str, end: &str, pool: &Arc<ChromeDriverPool>) -> anyhow::Result<Vec<EconomicEvent>> {
    let url = "https://www.finanzen.net/termine/wirtschaftsdaten/".to_string();
    let start_clone = start.to_string();
    let end_clone = end.to_string();

    let task = ScrapeTask::new(url, move |client| async move {
        goto_and_prepare(&client).await?;
        let mut all_events = Vec::new();
        let mut current = start_clone;

        while current <= end_clone {
            set_date_range(&client, &current, &end_clone).await?;
            tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
            let new_events = extract_events(&client).await?;
            if new_events.is_empty() { break; }
            all_events.extend(new_events.clone());

            let next = new_events.iter()
                .filter_map(|e| chrono::NaiveDate::parse_from_str(&e.date, "%Y-%m-%d").ok())
                .max()
                .and_then(|d| d.succ_opt())
                .map(|d| d.format("%Y-%m-%d").to_string())
                .unwrap_or(end_clone.clone());

            if next > end_clone { break; }
            current = next;
        }
        Ok(all_events)
    });

    // Use the pool for execution
    task.execute_with_pool(pool).await
}

pub fn process_batch(
    new_events: &[EconomicEvent],
    existing: &mut std::collections::HashMap<String, EconomicEvent>,
    today: &str,
) -> ScrapeResult {
    let mut changes = Vec::new();
    let mut removed = std::collections::HashSet::new();

    let identity_map = build_identity_lookup(existing);
    let date_map = build_date_event_lookup(existing);

    for new in new_events {
        let key = event_key(new);

        if let Some(old) = existing.get(&key) {
            changes.extend(detect_changes(old, new, today));
            existing.insert(key, new.clone());
            continue;
        }

        let date_key = format!("{}|{}|{}", new.country, new.event, new.date);
        if let Some(occurrences) = date_map.get(&date_key) {
            if let Some((old_key, old_event)) = occurrences.iter().find(|(k, _)| *k != key) {
                if new.date.as_str() > today {
                    changes.push(EventChange {
                        date: new.date.clone(),
                        event: new.event.clone(),
                        country: new.country.clone(),
                        field_changed: "time".to_string(),
                        old_value: old_event.time.clone(),
                        new_value: new.time.clone(),
                        detected_at: Local::now().format("%Y-%m-%d %H:%M:%S").to_string(),
                    });
                }
                removed.insert(old_key.clone());
                existing.remove(old_key);
            }
        }

        existing.insert(key, new.clone());
    }

    ScrapeResult { changes, removed_keys: removed }
}