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 feeds: Vec<RssFeed>,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct RssFeed {
    pub url: String,
    pub category: 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,
    pub category: String,
}

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

fn default_feeds() -> Vec<RssFeed> {
    vec![
        // 💻 Technik
        RssFeed {
            url: "https://www.heise.de/rss/heise-atom.xml".into(),
            category: "Technik".into(),
        },
        RssFeed {
            url: "https://www.golem.de/rss.php?feed=ATOM1.0".into(),
            category: "Technik".into(),
        },
        RssFeed {
            url: "https://www.theverge.com/rss/index.xml".into(),
            category: "Technik".into(),
        },
        RssFeed {
            url: "https://arstechnica.com/feed/".into(),
            category: "Technik".into(),
        },
        RssFeed {
            url: "https://www.phoronix.com/rss.php".into(),
            category: "Technik".into(),
        },
        // 📰 Nachrichten
        RssFeed {
            url: "https://www.tagesschau.de/xml/rss2".into(),
            category: "Nachrichten".into(),
        },
        RssFeed {
            url: "https://www.spiegel.de/schlagzeilen/index.rss".into(),
            category: "Nachrichten".into(),
        },
        RssFeed {
            url: "https://feeds.bbci.co.uk/news/technology/rss.xml".into(),
            category: "Nachrichten".into(),
        },
        RssFeed {
            url: "https://feeds.reuters.com/reuters/technologyNews".into(),
            category: "Nachrichten".into(),
        },
        // 🔭 Wissenschaft
        RssFeed {
            url: "https://www.nasa.gov/news-release/feed/".into(),
            category: "Wissenschaft".into(),
        },
        RssFeed {
            url: "https://www.sciencedaily.com/rss/computers_math/artificial_intelligence.xml"
                .into(),
            category: "Wissenschaft".into(),
        },
        RssFeed {
            url: "https://deepmind.google/blog/rss.xml".into(),
            category: "Wissenschaft".into(),
        },
        // 🤖 KI
        RssFeed {
            url: "https://openai.com/blog/rss.xml".into(),
            category: "KI".into(),
        },
        RssFeed {
            url: "https://venturebeat.com/feed/".into(),
            category: "KI".into(),
        },
        // 🐧 Open Source
        RssFeed {
            url: "https://lwn.net/headlines/rss".into(),
            category: "Open Source".into(),
        },
        RssFeed {
            url: "https://github.blog/feed/".into(),
            category: "Open Source".into(),
        },
    ]
}

#[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<RssFeed>, String> {
    let path = get_config_path(&app);
    let defaults = default_feeds();

    let existing_config: Option<RssConfig> = if path.exists() {
        let content = fs::read_to_string(&path).map_err(|e| e.to_string())?;
        ron::from_str(&content).ok()
    } else {
        None
    };

    // Datei fehlt ODER hat weniger als 3 Einträge → defaults schreiben
    let feeds = match existing_config {
        Some(config) if config.feeds.len() >= 3 => config.feeds,
        _ => {
            let config = RssConfig {
                feeds: defaults.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())?;
            defaults
        }
    };

    let mut lock = state.rss_config.lock().unwrap();
    lock.feeds = feeds.clone();
    Ok(feeds)
}

#[tauri::command]
pub async fn save_rss_urls(
    feeds: Vec<RssFeed>,
    app: AppHandle,
    state: State<'_, NewsState>,
) -> Result<(), String> {
    let config = RssConfig { feeds };
    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(),
        category: "KI".into(),
    }])
}

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

    for feed_cfg in feeds {
        if let Ok(res) = client.get(&feed_cfg.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,
                            category: feed_cfg.category.clone(),
                        });
                    }
                }
            }
        }
    }
    Ok(all_articles)
}
