use crate::util::requester;
use dashmap::DashMap;
use once_cell::sync::Lazy;
use serde_json::json;
use std::error::Error;
use std::fmt::Write as _;
use std::time::{SystemTime, UNIX_EPOCH};

// Global cache: Map<ErrorSignature, LastSentTimestamp>
static ERROR_CACHE: Lazy<DashMap<String, u64>> = Lazy::new(DashMap::new);
// const COOLDOWN_SECONDS: u64 = 3600; // 1 Hour cooldown

#[allow(dead_code)]
pub fn format_error_chain(err: &dyn Error) -> String {
    let mut chain_str = String::new();
    let mut current_err: Option<&dyn Error> = Some(err);
    let mut index = 1;
    while let Some(e) = current_err {
        let _ = writeln!(chain_str, "{}. {}", index, e);
        current_err = e.source();
        index += 1;
    }
    chain_str
}

pub async fn send_discord_error_report(
    error_msg: String,
    error_chain: Option<String>,
    context: Option<&str>,
    extra_info: Option<&str>,
    file: &str,
    line: u32,
    module: &str,
) {
    let now = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map(|d| d.as_secs())
        .unwrap_or(0);

    // --- Deduplication Logic ---
    // Create a unique key based on error content and location
    let error_signature = format!("{}-{}-{}", error_msg, file, line);

    if let Some(_) = ERROR_CACHE.get(&error_signature) {
        // if now - *last_sent < COOLDOWN_SECONDS {
        // Error is still in cooldown, skip sending
        return;
        // }
    }

    // Update the cache with the current timestamp
    ERROR_CACHE.insert(error_signature, now);
    // ---------------------------

    const MAX_FIELD: usize = 1024;
    let truncate = |s: &str| {
        if s.len() > MAX_FIELD {
            format!("{}…", &s[..MAX_FIELD - 1])
        } else {
            s.to_string()
        }
    };

    let payload = json!({
        "embeds": [{
            "title": "🚨 Rust Error Report",
            "color": 0xE74C3C,
            "fields": [
                {
                    "name": "Error",
                    "value": format!("```{}```", truncate(&error_msg)),
                    "inline": false
                },
                {
                    "name": "Error Chain",
                    "value": truncate(&error_chain.unwrap_or_else(|| "No chain provided".to_string())),
                    "inline": false
                },
                {
                    "name": "Location",
                    "value": format!("`{}`:{}\n`{}`", file, line, module),
                    "inline": true
                },
                {
                    "name": "Context",
                    "value": truncate(context.unwrap_or("n/a")),
                    "inline": true
                },
                {
                    "name": "Extra Info",
                    "value": truncate(extra_info.unwrap_or("n/a")),
                    "inline": false
                }
            ],
            "footer": {
                "text": format!("Unix time: {} | Cooldown active", now)
            }
        }]
    });

    let webhook_url = match std::env::var("DISCORD_WEBHOOK") {
        Ok(url) => url,
        Err(_) => {
            // println!("{:#?}", &payload);
            return;
        }
    };
    let mut requester = requester::Requester::new();
    let _ = requester.post_json(&webhook_url, &payload, vec![]).await;
}
