use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;
use std::sync::Mutex;
use tauri::{AppHandle, Manager, State};

#[derive(Serialize, Deserialize, Default, Clone)]
pub struct RssConfig {
    pub urls: Vec<String>,
}

#[derive(Default)]
pub struct NewsState {
    pub openrouter_key: Mutex<String>,
    pub groq_key: Mutex<String>,
    pub rss_config: Mutex<RssConfig>,
}

#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct NewsArticle {
    pub content: String,
    pub author: String,
    pub created_at: String,
}

fn get_config_path(app: &AppHandle) -> PathBuf {
    app.path()
        .app_config_dir()
        .unwrap_or_else(|_| PathBuf::from("."))
        .join("rss.ron")
}

#[tauri::command]
pub async fn save_openrouter_key(key: String, state: State<'_, NewsState>) -> Result<(), String> {
    let mut lock = state.openrouter_key.lock().map_err(|_| "Lock failed")?;
    *lock = key.trim().to_string();
    Ok(())
}

#[tauri::command]
pub async fn save_groq_key(key: String, state: State<'_, NewsState>) -> Result<(), String> {
    let mut lock = state.groq_key.lock().map_err(|_| "Lock failed")?;
    *lock = key.trim().to_string();
    Ok(())
}

#[tauri::command]
pub async fn load_rss_config(
    app: AppHandle,
    state: State<'_, NewsState>,
) -> Result<Vec<String>, String> {
    let path = get_config_path(&app);
    if !path.exists() {
        let default_urls = vec![
            "https://www.nasa.gov/news-release/feed/".to_string(),
            "https://www.heise.de/rss/heise-atom.xml".to_string(),
        ];
        let config = RssConfig {
            urls: default_urls.clone(),
        };
        if let Some(parent) = path.parent() {
            fs::create_dir_all(parent).map_err(|e| e.to_string())?;
        }
        let ron_str = ron::to_string(&config).map_err(|e| e.to_string())?;
        fs::write(&path, ron_str).map_err(|e| e.to_string())?;
        let mut lock = state.rss_config.lock().unwrap();
        lock.urls = default_urls.clone();
        return Ok(default_urls);
    }
    let content = fs::read_to_string(path).map_err(|e| e.to_string())?;
    let config: RssConfig = ron::from_str(&content).map_err(|e| e.to_string())?;
    let mut lock = state.rss_config.lock().unwrap();
    *lock = config.clone();
    Ok(config.urls)
}

#[tauri::command]
pub async fn save_rss_urls(
    urls: Vec<String>,
    app: AppHandle,
    state: State<'_, NewsState>,
) -> Result<(), String> {
    let config = RssConfig { urls };
    let path = get_config_path(&app);
    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent).map_err(|e| e.to_string())?;
    }
    let ron_str = ron::to_string(&config).map_err(|e| e.to_string())?;
    fs::write(path, ron_str).map_err(|e| e.to_string())?;
    let mut lock = state.rss_config.lock().unwrap();
    *lock = config;
    Ok(())
}

#[tauri::command]
pub async fn fetch_ai_news(
    provider: String,
    state: State<'_, NewsState>,
) -> Result<Vec<NewsArticle>, String> {
    let (key, url, model, author) = match provider.as_str() {
        "groq" => {
            let k = state.groq_key.lock().map_err(|_| "Lock failed")?.clone();
            (
                k,
                "https://api.groq.com/openai/v1/chat/completions",
                "llama-3.1-8b-instant",
                "Groq AI",
            )
        }
        _ => {
            let k = state
                .openrouter_key
                .lock()
                .map_err(|_| "Lock failed")?
                .clone();
            (
                k,
                "https://openrouter.ai/api/v1/chat/completions",
                "openai/gpt-oss-20b:free:online",
                "OpenRouter AI",
            )
        }
    };

    if key.is_empty() {
        return Err(format!("API Key für {} fehlt.", author));
    }

    let client = reqwest::Client::new();
    let response = client
        .post(url)
        .header("Authorization", format!("Bearer {}", key))
        .json(&serde_json::json!({
            "model": model,
            "messages": [
                {"role": "system", "content": "Kurze Tech-News, 1-2 Sätze, Deutsch. Nutze Markdown."},
                {"role": "user", "content": "Was gibt es neues in der Tech-Welt?"}
            ]
        }))
        .send()
        .await
        .map_err(|e| e.to_string())?;

    let json: serde_json::Value = response.json().await.map_err(|e| e.to_string())?;
    let content = json["choices"][0]["message"]["content"]
        .as_str()
        .unwrap_or("Fehler beim Abrufen der Inhalte")
        .to_string();

    Ok(vec![NewsArticle {
        content,
        author: author.into(),
        created_at: "Gerade eben".into(),
    }])
}

#[tauri::command]
pub async fn fetch_rss_news(state: State<'_, NewsState>) -> Result<Vec<NewsArticle>, String> {
    let urls = state.rss_config.lock().unwrap().urls.clone();
    let mut all_articles = Vec::new();
    let client = reqwest::Client::new();

    for url in urls {
        if let Ok(res) = client.get(&url).send().await {
            if let Ok(bytes) = res.bytes().await {
                if let Ok(feed) = feed_rs::parser::parse(&bytes[..]) {
                    let source = feed
                        .title
                        .map(|t| t.content)
                        .unwrap_or_else(|| "RSS".into());
                    for entry in feed.entries.into_iter().take(3) {
                        let date = entry
                            .published
                            .or(entry.updated)
                            .map(|d| d.format("%d.%m.%Y %H:%M").to_string())
                            .unwrap_or_else(|| "--.--.----".into());

                        all_articles.push(NewsArticle {
                            content: format!(
                                "### {}\n\n{}",
                                entry.title.map(|t| t.content).unwrap_or_default(),
                                entry.summary.map(|s| s.content).unwrap_or_default()
                            ),
                            author: source.clone(),
                            created_at: date,
                        });
                    }
                }
            }
        }
    }
    Ok(all_articles)
}
