#!/usr/bin/env python3
"""
Geopolitics News and Analysis Gatherer
Fetches RSS feeds, separates news vs analysis, ensures balanced perspectives.
Uses only standard library (urllib, xml.etree) to avoid external dependencies.
"""
import sys
import os
import hashlib
from datetime import datetime
from urllib.request import urlopen, Request
from urllib.error import URLError, HTTPError
import xml.etree.ElementTree as ET

# Feed list: (url, category, perspective, source_name)
# category: 'news' or 'analysis'
# perspective: 'west', 'russia', 'china', 'belarus', 'alternative'
FEEDS = [
    # Analysis - Think tanks
    ("https://carnegie.ru/rss", "analysis", "russia", "Carnegie Moscow Center"),
    ("https://www.rusi.org/rss.xml", "analysis", "west", "RUSI"),
    ("https://meduza.io/rss/all", "analysis", "russia", "Meduza"),
    ("https://www.chathamhouse.org/rss.xml", "analysis", "west", "Chatham House"),
    # China / multipolarity
    ("https://www.scmp.com/rss/91/feed", "news", "china", "South China Morning Post"),
    ("https://www.globaltimes.cn/rss/outbrain.xml", "news", "china", "Global Times"),
    ("https://thediplomat.com/feed/", "news", "west", "The Diplomat"),
    # Belarus
    ("https://www.currenttime.tv/api/feed/rss", "news", "belarus", "Настоящее Время"),
    ("https://spring96.org/rss", "news", "belarus", "Spring96"),
    # Alternative western view
    ("https://www.rt.com/rss/", "news", "russia", "RT"),
    ("https://multipolarista.com/feed/", "analysis", "alternative", "Multipolarista"),
    ("https://geopoliticalfutures.com/feed/", "analysis", "west", "Geopolitical Futures"),
    # AI / LLM
    ("https://www.anthropic.com/news", "news", "west", "Anthropic Blog"),
    ("https://openai.com/blog/rss", "news", "west", "OpenAI Blog"),
    ("https://huggingface.co/blog/feed.xml", "news", "west", "Hugging Face Blog"),
    ("https://simonwillison.net/atom/everything/", "news", "west", "Simon Willison"),
    ("https://www.deeplearning.ai/the-batch/feed/", "news", "west", "The Batch"),
    # Python / DevTools
    ("https://realpython.com/atom.xml", "news", "west", "Real Python"),
    ("https://planetpython.org/rss20.xml", "news", "west", "Planet Python"),
    ("https://changelog.com/podcast.rss", "news", "west", "Changelog Podcast"),
    # Яхтинг
    ("https://www.sailmagazine.com/feed", "news", "west", "Sail Magazine"),
    ("https://www.yachtingworld.com/feed", "news", "west", "Yachting World"),
    ("https://cruisersforum.com/forums/-/index.rss", "news", "west", "Cruisers Forum"),
    # Стартапы / инди-хакеры
    ("https://www.indiehackers.com/feed.rss", "news", "west", "Indie Hackers"),
    ("https://news.ycombinator.com/rss", "news", "west", "Hacker News"),
    # Русскоязычный AI
    ("https://habr.com/ru/rss/hubs/artificial_intelligence/articles/", "news", "russia", "Habr AI"),
    ("https://habr.com/ru/rss/hubs/python/articles/", "news", "russia", "Habr Python"),
    # Общие русскоязычные источники
    ("https://lenta.ru/rss", "news", "russia", "Lenta.ru"),
    ("https://habr.com/ru/rss/all/", "news", "russia", "Habr"),
]

def fetch_feed(url):
    """Fetch and parse an RSS feed using urllib and ElementTree."""
    print(f"Fetching {url}")
    try:
        req = Request(url, headers={'User-Agent': 'Mozilla/5.0'})
        with urlopen(req, timeout=10) as response:
            data = response.read()
        # Parse XML
        root = ET.fromstring(data)
        # Find channel/item
        # RSS: channel/item
        # Atom: feed/entry
        items = []
        # Try RSS
        for elem in root.iter('item'):
            title = elem.findtext('title', default='No title')
            link = elem.findtext('link', default='#')
            pub_date = elem.findtext('pubDate', default='')
            if not pub_date:
                pub_date = elem.findtext('published', default='')
            if not pub_date:
                pub_date = elem.findtext('date', default='Unknown date')
            # description
            description = elem.findtext('description', default='')
            if not description:
                description = elem.findtext('{http://purl.org/rss/1.0/modules/content/}encoded', default='')
            # image from enclosure
            image_url = ''
            for enc in elem.findall('enclosure'):
                if enc.get('type', '').startswith('image/'):
                    image_url = enc.get('url', '')
                    break
            # fallback: media:content
            if not image_url:
                for media in elem.findall('{http://search.yahoo.com/mrss/}content'):
                    if media.get('medium', '').lower() == 'image':
                        image_url = media.get('url', '')
                        break
            items.append({
                'title': title.strip(),
                'link': link.strip(),
                'published': pub_date.strip(),
                'description': description.strip(),
                'image_url': image_url,
            })
        # Try Atom
        if not items:
            for elem in root.iter('{http://www.w3.org/2005/Atom}entry'):
                title = elem.findtext('{http://www.w3.org/2005/Atom}title', default='No title')
                link_elem = elem.find('{http://www.w3.org/2005/Atom}link')
                link = link_elem.get('href') if link_elem is not None else '#'
                pub_date = elem.findtext('{http://www.w3.org/2005/Atom}updated', default='')
                if not pub_date:
                    pub_date = elem.findtext('{http://www.w3.org/2005/Atom}published', default='Unknown date')
                # description (summary)
                description = elem.findtext('{http://www.w3.org/2005/Atom}summary', default='')
                if not description:
                    description = elem.findtext('{http://www.w3.org/2005/Atom}content', default='')
                # image from link rel="enclosure" or content
                image_url = ''
                # In Atom, image might be in a link with rel="enclosure" or in content
                for link_elem in elem.findall('{http://www.w3.org/2005/Atom}link'):
                    if link_elem.get('rel') == 'enclosure' and link_elem.get('type', '').startswith('image/'):
                        image_url = link_elem.get('href', '')
                        break
                # fallback: look for <media:thumbnail> or <media:content> in content? We'll skip for simplicity.
                items.append({
                    'title': title.strip(),
                    'link': link.strip(),
                    'published': pub_date.strip(),
                    'description': description.strip(),
                    'image_url': image_url,
                })
        return items
    except HTTPError as e:
        print(f"HTTP error fetching {url}: {e.code} {e.reason}")
        return []
    except URLError as e:
        print(f"URL error fetching {url}: {e.reason}")
        return []
    except ET.ParseError as e:
        print(f"XML parse error for {url}: {e}")
        return []
    except Exception as e:
        print(f"Unexpected error processing {url}: {e}")
        return []

def entry_id(item):
    """Create a stable ID for an item."""
    if item['link'] and item['link'] != '#':
        return item['link']
    # fallback to title+published
    return hashlib.md5((item['title'] + item['published']).encode()).hexdigest()

def main():
    output_lines = []
    output_lines.append("# Геополитический дайджест\n")
    output_lines.append(f"*Сгенерировано: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*\n")
    
    news_items = []   # list of dicts with keys: title, link, published, source, perspective, description, image_url
    analysis_items = []
    
    for url, category, perspective, source_name in FEEDS:
        try:
            items = fetch_feed(url)
            for item in items[:10]:  # limit to latest 10 per feed
                item_with_meta = item.copy()
                item_with_meta['source'] = source_name
                item_with_meta['perspective'] = perspective
                item_with_meta['category'] = category
                if category == 'news':
                    news_items.append(item_with_meta)
                else:
                    analysis_items.append(item_with_meta)
        except Exception as e:
            print(f"Error processing {url}: {e}")
    
    # Deduplicate by link (or ID) within each category
    seen_news = set()
    unique_news = []
    for item in news_items:
        eid = entry_id(item)
        if eid not in seen_news:
            seen_news.add(eid)
            unique_news.append(item)
    
    seen_analysis = set()
    unique_analysis = []
    for item in analysis_items:
        eid = entry_id(item)
        if eid not in seen_analysis:
            seen_analysis.add(eid)
            unique_analysis.append(item)
    
    output_lines.append("## Новости (Что происходит)\n")
    if unique_news:
        for item in unique_news[:20]:  # limit total output
            output_lines.append(f"- [{item['title']}]({item['link']}) — *{item['source']}* ({item['perspective']}) — {item['published']}")
            if item['description']:
                # Truncate description to 200 chars and strip newlines
                desc = item['description'].strip().replace('\n', ' ')
                if len(desc) > 200:
                    desc = desc[:200] + '...'
                output_lines.append(f"  {desc}")
            if item['image_url']:
                output_lines.append(f"  ![]({item['image_url']})")
    else:
        output_lines.append("_Новостей не найдено._")
    output_lines.append("\n")
    
    output_lines.append("## Анализ (Почему и что будет)\n")
    if unique_analysis:
        for item in unique_analysis[:20]:
            output_lines.append(f"- [{item['title']}]({item['link']}) — *{item['source']}* ({item['perspective']}) — {item['published']}")
            if item['description']:
                # Truncate description to 200 chars and strip newlines
                desc = item['description'].strip().replace('\n', ' ')
                if len(desc) > 200:
                    desc = desc[:200] + '...'
                output_lines.append(f"  {desc}")
            if item['image_url']:
                output_lines.append(f"  ![]({item['image_url']})")
    else:
        output_lines.append("_Аналитических материалов не найдено._")
    output_lines.append("\n")
    
    output_lines.append("---\n")
    output_lines.append("*Принцип чтения: для каждой темы минимум 2 источника с разных сторон.*\n")
    
    output_path = os.path.expanduser("~/geopolitics-digest.md")
    with open(output_path, "w", encoding="utf-8") as f:
        f.write("\n".join(output_lines))
    
    print(f"Digest written to {output_path}")

if __name__ == "__main__":
    main()
