#!/usr/bin/env python3
"""Fetch 10 board game designer bios from BGG and store in Letta.
Cron job: crawls BGG Top 200, extracts designers, stores biographies."""
import urllib.request, urllib.parse, urllib.error
import xml.etree.ElementTree as ET
import json, time, re, html, sys, os

BGG_API_KEY = "de3b01db-9be3-4c80-bd80-d47e071b320e"
BGG_BASE = "https://boardgamegeek.com/xmlapi2"
UA = "BSN-OpenClaw/1.0 (Brettspiel-News.de; kontakt@brettspiel-news.de)"
LETTA_AGENT = "http://127.0.0.1:8283/v1/agents/agent-4b5df3c4-00b8-4c07-b8f4-d38246b7eecd"
SLEEP = 1.5  # BGG rate limit

# Helper: call hairy BGG XML API v2 with retries
def bgg_api(endpoint, params, timeout=20, retries=2):
    url = f"{BGG_BASE}/{endpoint}"
    if params:
        url += "?" + urllib.parse.urlencode(params)
    req = urllib.request.Request(url, headers={
        "User-Agent": UA,
        "Authorization": f"Bearer {BGG_API_KEY}"
    })
    for attempt in range(retries):
        time.sleep(SLEEP)
        try:
            with urllib.request.urlopen(req, timeout=timeout) as resp:
                if resp.status == 202:
                    time.sleep(4)
                    with urllib.request.urlopen(req, timeout=timeout) as r2:
                        data = r2.read()
                else:
                    data = resp.read()
            return ET.fromstring(data)
        except Exception as e:
            if attempt < retries - 1:
                time.sleep(3)
                continue
            raise e

# Helper: call Letta REST API
def letta_get(path, params=None):
    url = f"{LETTA_AGENT}{path}"
    if params:
        url += "?" + urllib.parse.urlencode(params)
    try:
        req = urllib.request.Request(url)
        with urllib.request.urlopen(req, timeout=10) as resp:
            return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        body = e.read().decode() if e.fp else ""
        print(f"  Letta GET error {e.code}: {body[:200]}")
        return {"results": []}

def letta_post(path, data):
    url = f"{LETTA_AGENT}{path}"
    body = json.dumps(data).encode("utf-8")
    req = urllib.request.Request(
        url, data=body,
        headers={"Content-Type": "application/json"},
        method="POST"
    )
    try:
        with urllib.request.urlopen(req, timeout=15) as resp:
            return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        body = e.read().decode() if e.fp else ""
        print(f"  Letta POST error {e.code}: {body[:200]}")
        raise

def search_letta(query, limit=10):
    return letta_get("/archival-memory/search", {"query": query, "limit": limit})

def store_in_letta(text):
    return letta_post("/archival-memory", {"text": text[:5000]})

def is_already_stored(designer_name, designer_id):
    """Check if designer already exists in Letta as structured entry."""
    hits = search_letta(f"AUTOR: {designer_name}", limit=5)
    for r in hits.get("results", []):
        if f"AUTOR: {designer_name} · BGG-ID: {designer_id}" in r.get("content", ""):
            return True
    # Also check by BGG-ID
    hits2 = search_letta(f"BGG-ID: {designer_id}", limit=5)
    for r in hits2.get("results", []):
        if f"BGG-ID: {designer_id}" in r.get("content", ""):
            return True
    return False

def get_designer_games(designer_name, designer_id, known_games_ids=None):
    """Fetch games verified as designed by this designer, with BGG ranks."""
    verified = []
    
    if known_games_ids:
        # Try batch
        for i in range(0, len(known_games_ids), 10):
            batch = known_games_ids[i:i+10]
            try:
                root = bgg_api("thing", {"id": ",".join(batch), "stats": "1"}, timeout=25)
                for item in root.findall(".//item"):
                    gid = item.get("id")
                    name_el = item.find('.//name[@type="primary"]')
                    if name_el is None:
                        continue
                    gname = name_el.get("value", "")
                    designers = [l.get("value", "") for l in item.findall('.//link[@type="boardgamedesigner"]')]
                    if designer_id in [l.get("id", "") for l in item.findall('.//link[@type="boardgamedesigner"]')]:
                        pass  # matched by ID
                    elif designer_name not in " ".join(designers):
                        continue
                    rank = None
                    ratings = item.find(".//ratings")
                    if ratings is not None:
                        ranks_el = ratings.find(".//ranks")
                        if ranks_el is not None:
                            for r in ranks_el.findall(".//rank"):
                                if r.get("type") == "subtype":
                                    rv = r.get("value", "")
                                    if rv and rv != "Not Ranked":
                                        rank = rv
                                        break
                    verified.append({"id": gid, "name": gname, "rank": rank})
            except Exception as e:
                print(f"    Batch error: {e}")
    
    # Try searching by designer name for more games
    try:
        root = bgg_api("search", {"query": designer_name, "type": "boardgame,boardgameexpansion", "exact": "1"}, timeout=15)
        more_ids = []
        for item in root.findall(".//item"):
            gid = item.get("id")
            if gid and gid not in [g["id"] for g in verified]:
                more_ids.append(gid)
        
        # Verify these too
        for i in range(0, min(len(more_ids), 30), 10):
            batch = more_ids[i:i+10]
            try:
                root2 = bgg_api("thing", {"id": ",".join(batch), "stats": "1"}, timeout=25)
                for item in root2.findall(".//item"):
                    gid = item.get("id")
                    name_el = item.find('.//name[@type="primary"]')
                    if name_el is None:
                        continue
                    gname = name_el.get("value", "")
                    linked_ids = set(l.get("id", "") for l in item.findall('.//link[@type="boardgamedesigner"]'))
                    if designer_id not in linked_ids:
                        continue
                    rank = None
                    ratings = item.find(".//ratings")
                    if ratings is not None:
                        ranks_el = ratings.find(".//ranks")
                        if ranks_el is not None:
                            for r in ranks_el.findall(".//rank"):
                                if r.get("type") == "subtype":
                                    rv = r.get("value", "")
                                    if rv and rv != "Not Ranked":
                                        rank = rv
                                        break
                    verified.append({"id": gid, "name": gname, "rank": rank})
            except Exception as e:
                print(f"    Verify batch error: {e}")
    except Exception as e:
        print(f"    Search error: {e}")
    
    # Sort by rank (best first)
    ranked = sorted([g for g in verified if g.get("rank") and g["rank"].isdigit()], key=lambda x: int(x["rank"]))
    unranked = [g for g in verified if not g.get("rank") or not g["rank"].isdigit()]
    
    return ranked + unranked, len(ranked) + len(unranked)

# ===== DESIGNER DATABASE =====
# Known game IDs for each designer to speed up BGG lookups
DESIGNER_GAMES = {
    # Reiner Knizia (BGG-ID: 2) - over 300 games published
    "2": {
        "name": "Reiner Knizia",
        "nationality": "Deutschland",
        "year": "1957",
        "mechanisms": "Auktionen, Bluffen, Mehrheiten, Set Collection, Area Control, Tile Placement, Hand Management",
        "bio": "Einer der produktivsten und meistausgezeichneten Spieleautoren der Welt mit über 300 Publikationen. Geboren in Deutschland, lebt heute in England. Nach dem Studium der Mathematik arbeitete er im Bank- und Versicherungswesen, bevor er sich ab den 1990er Jahren ganz dem Spieledesign widmete. Seine Spiele zeichnen sich durch elegante, mathematisch präzise Regeln und tiefe strategische Entscheidungen aus.",
        "game_ids": ["12","54","18","2955","366","39683","11","92","427","20262","170","2636","172","178","124","17","40628","47","13","50","576","188","198","193","2591","433","1782","28021","919","214","358","41","2165","38453","939","3","96","148","153","227","673","254","230","311","5","1864","1863","1852","3402","4098","372","1017","1125","189","206","1335","1510","1535","1536","1614","1754","1795","1796","1831","1845","1865","1866","1868","1875","1877","1878","1879","1915","1918","1922","1923","1924","1925","1927","1930","1962","1964","1966","1968","1972","1974","1975","1977","1982","1986","1990","1993","1994","2003","2006","2007","2018","15062"]  # Tigris & Euphrates 42, Modern Art 12, Ra 2955, Lost Cities 50
    },
    # Uwe Rosenberg (BGG-ID: 10)
    "10": {
        "name": "Uwe Rosenberg",
        "nationality": "Deutschland",
        "year": "1970",
        "mechanisms": "Worker Placement, Card Drafting, Engine Building, Farming-Simulation, Tile Placement, Resource Management",
        "bio": "Der gelernte Statistiker und Buchhalter begann seine Karriere mit Bohnanza (1997), einem Kartenspiel um Bohnenfelder, das bis heute zu den beliebtesten Kartenspielen zählt. Ab den 2000er Jahren etablierte er sich mit komplexeren Worker-Placement-Spielen wie Agricola, Caverna und A Feast for Odin. Er gilt als Pionier des Worker-Placement-Mechanismus und veröffentlicht regelmäßig Spiele, die in den BGG Top 100 platziert sind.",
        "game_ids": ["31260","102794","183436","172931","28143","163068","41163","500","180263","131483","126467","67361","55600","205059","66773","12005","24068","215311","385432","290318","169786","193737","342900"]
    },
    # Stefan Feld (BGG-ID: 4958)
    "4958": {
        "name": "Stefan Feld",
        "nationality": "Deutschland",
        "year": "1968",
        "mechanisms": "Würfelmechaniken, Point Salad, Mehrere Wege zum Sieg, Aktionsmanagement, Rondell",
        "bio": "Der studierte Psychologe und Gymnasiallehrer gehört zu den profiliertesten deutschen Spieleautoren der 2000er Jahre. Sein Durchbruch gelang mit Die Burgen von Burgund (2011), das auf BGG dauerhaft in den Top 20 rangiert. Felds Spiele zeichnen sich durch ausgefeilte Würfelmechaniken aus und bieten oft mehrere gleichwertige Wege zum Sieg (Point-Salad-Prinzip).",
        "game_ids": ["84876","102262","363622","107976","56903","102262","73037","80373","82591","85963","95547","97786","130886","133817","148618","156329","157378","168520","169207","178127","183897","187390","203332","235283","253680","267350","268271","297547","386857","427127"]
    },
    # Alexander Pfister (BGG-ID: 11767)
    "11767": {
        "name": "Alexander Pfister",
        "nationality": "Österreich",
        "year": "1972",
        "mechanisms": "Hand Management, Deck Building, Route Building, Rondell, Engine Building",
        "bio": "Der Österreicher arbeitete als Projektmanager und Programmierer, bevor er hauptberuflich Spieleautor wurde. Seinen internationalen Durchbruch feierte er mit Great Western Trail (2016), das auf Anhieb in die BGG Top 30 einstieg. Pfisters Spiele verbinden Deck Building mit Hand Management und innovativen Rondell-Systemen.",
        "game_ids": ["193738","183840","193042","157354","284330","337627","372165","380607","381213","382146","391620","401816","419652"]
    },
    # Wolfgang Kramer (BGG-ID: 7)
    "7": {
        "name": "Wolfgang Kramer",
        "nationality": "Deutschland",
        "year": "1942",
        "mechanisms": "Area Control, Mehrheiten, Aktionspunkte, Hidden Movement, Rondell, Route Building",
        "bio": "Er ist einer der Pioniere des modernen deutschen Brettspiels und der erste Autor, der viermal das Spiel des Jahres gewann (Auf Achse, Heimlich & Co., El Grande, Tikal). Der gelernte Maschinenbauer begann in den 1970er Jahren mit ersten Spielveröffentlichungen. Kramer prägte das Genre der strategischen Eurogames maßgeblich mit und arbeitete oft mit Michael Kiesling zusammen.",
        "game_ids": ["13","49","104","73","119","198","192","177","91","98","103","71","5617","172","589","632","370","369","56","207","210","211","212","213","214","215","216","217","218","219","220","221","222","224","225","226","227","228","229","230","231","233","234","235","236","237","238"]
    },
    # Rüdiger Dorn (BGG-ID: 9216)
    "9216": {
        "name": "Rüdiger Dorn",
        "nationality": "Deutschland",
        "year": "1968",
        "mechanisms": "Auktionsmechaniken, Set Collection, Aktionsmanagement, Hand Management",
        "bio": "Der gelernte Bankkaufmann und Spieleautor feierte seinen Durchbruch mit Goa (2004), einem Wirtschaftsspiel über den Gewürzhandel, das zu den Klassikern des Eurogame-Genres zählt. Dorn ist bekannt für elegante Auktions- und Handelsmechaniken. Weitere bekannte Spiele sind Jambo, Luxor und Karuba.",
        "game_ids": ["9216","27725","37111","51798","141043","148122","184267","189932","222607","246931","373458"]
    },
    # Mac Gerdts (BGG-ID: 6045)
    "6045": {
        "name": "Mac Gerdts",
        "nationality": "Deutschland",
        "year": "1965",
        "mechanisms": "Rondell-System, Economic Simulation, Hand Management, Area Control",
        "bio": "Der Ökonom und Unternehmensberater ist Erfinder des populären Rondell-Mechanismus, bei dem Spieler auf einem kreisförmigen Pfad ihre Aktionen wählen. Sein Meisterwerk Concordia (2013) ist ein zeitloses Handelsspiel, das konstant in den BGG Top 30 rangiert. Gerdts entwickelte zuvor bereits Imperial und Imperial 2030, zwei hochgelobte Spiele über die europäische Börsen- und Machtpolitik.",
        "game_ids": ["124361","24181","32470","465819","99335","17324","97089","106098","29124","105559","56958","104241"]
    },
    # Simone Luciani (BGG-ID: 35418)
    "35418": {
        "name": "Simone Luciani",
        "nationality": "Italien",
        "year": "1974",
        "mechanisms": "Worker Placement, Dice Drafting, Card Drafting, Engine Building, Aktionsmanagement",
        "bio": "Der italienische Spieleautor aus Bologna hat sich seit den 2010er Jahren als einer der führenden Autoren des Eurogame-Genres etabliert. Gemeinsam mit Virginio Gigli entwickelte er Klassiker wie Grand Austria Hotel, Lorenzo il Magnifico und Marco Polo. Lucianis Spiele zeichnen sich durch elegante Worker-Placement- und Dice-Drafting-Mechaniken aus.",
        "game_ids": ["183877","208566","222150","234356","236441","236548","252551","256263","283896","285967","319509","325919","326380","347140","410780","421378","426800","428152","431776","434367","441069","447383","462437"]
    },
    # Bruno Cathala (BGG-ID: 1727)
    "1727": {
        "name": "Bruno Cathala",
        "nationality": "Frankreich",
        "year": "1971",
        "mechanisms": "Tile Placement, Card Drafting, Set Collection, Deduction, Hand Management",
        "bio": "Der französische Spieleautor begann seine Karriere bei der Zeitung Le Monde und ist seit über 20 Jahren hauptberuflich Spieleentwickler. Zusammen mit Antoine Bauza schuf er 7 Wonders Duel, das bis heute zu den beliebtesten Zweispieler-Spielen zählt. Zu seinen weiteren Erfolgen gehören Kingdomino (Spiel des Jahres 2017), Mr. Jack, Cyclades und Five Tribes.",
        "game_ids": ["84962","173346","170786","203420","54043","372","274426","24076","127345","132531","103287","68866","176494","128928","15512","84762","147151","20342","371942","251412","118763","117915","71189","66097","270846","262560","152313","199791","229915","270902","314040","342124","357599","374528","382209","402688","423623","432690","449544","452284"]
    },
    # Antoine Bauza (BGG-ID: 9714)
    "9714": {
        "name": "Antoine Bauza",
        "nationality": "Frankreich",
        "year": "1978",
        "mechanisms": "Card Drafting, Cooperative, Engine Building, Tile Placement, Set Collection",
        "bio": "Der französische Spieleautor wurde mit 7 Wonders (2010) schlagartig international bekannt, das über 1 Million Mal verkauft wurde und als eines der einflussreichsten Spiele der 2010er Jahre gilt. Bauza studierte zunächst Architektur, bevor er sich ganz dem Spieledesign widmete. Seine Spiele zeichnen sich durch elegantes Card Drafting und innovative Kooperationsmechaniken aus.",
        "game_ids": ["68448","173346","123540","124042","155873","172166","178900","186260","190023","190400","198320","198773","205347","209542","209683","213779","221223","227466","240414","246187","252094","256021","270456","270639","284362","315869","317188","322949","323514","324710","327855","340158","341188","344839","358783","362709","367292","381178","381242","382020","383803","385261","385550","387495","388152","390744","390816","394242","394880","398200","399431","400562","402979","403151","403466","406538","407912","409286","409858","410481","416472","417249","417966","418419","423427","425247","425391","425473","427011","427932","428782","430925","432134","432483","433206","434324","434620","434916","435025","435271","437047","437408","438347","440127","441855","444329","444799","445580","451588","453830","466281","466949","467660"]
    },
    # Michael Kiesling (BGG-ID: 42)
    "42": {
        "name": "Michael Kiesling",
        "nationality": "Deutschland",
        "year": "1962",
        "mechanisms": "Tile Placement, Area Control, Mehrheiten, Aktionspunkte, Würfelmechaniken",
        "bio": "Der deutsche Spieleautor gehört seit den 1990er Jahren zu den erfolgreichsten Autoren des Landes. In Zusammenarbeit mit Wolfgang Kramer entstanden Klassiker wie Tikal, Mexica und Java, die das Genre der Area-Control-Spiele prägten. Kiesling ist bekannt für innovative Tile-Placement-Systeme und elegante Mehrheitsmechaniken.",
        "game_ids": ["49","104","73","71","5719","5413","262560","128928","12005","24068","24181","5432","26599","36748","65520","77289","82424","85537","94128","98959","118763","121093","126979","128882","129595","129596","132531","134143","135444","140795","145604","151508","156223","156366","166482","166968","170216","181328","187938","188861","188866","198724","199212","199792","204359","204429","212773","222152","228663","229624","232627","234426","236236","237310","242704","244432","244485","245756","248590","252044","255156","260055","264052","267347","267622","268375","271186","274385","276315","283675","283834","286623","293141","296160","306458","306544","317763","321853","324065","331257","331632","332048","343160","344791","349348","351540","357284","359333","364298","366479","371305","371688","371745","372840","372978","378189","378939","379051","380219","380525","383372","383497","384442","387657","389519","394914","395771","398580","399727","401476","402022","402745","413316","414202","416065","418076","419160","419699","421305","422269","426838","429706","430543","433049","433568","433788","434997","435559","435802","436619","436923","438664","440085","441062","441728","443707","443895","445480","445625","447122","448570","449377","451755","452621","455060","455404","456332","458032","458223","458380","458677","459640","460254","460382","462138","462979","463349","464116","465495","465605","466074","466243","466875","468072","469330","469884","470181","470522","471224","471485","472065","473048","474032","474198","474310","474526","475231","476224"]
    },
    # Leo Colovini (BGG-ID: 138)
    "138": {
        "name": "Leo Colovini",
        "nationality": "Italien",
        "year": "1952",
        "mechanisms": "Deduction, Set Collection, Area Control, Mehrheiten, Bluffen",
        "bio": "Der italienische Spieleautor aus Venedig ist spezialisiert auf deduktive Denkspiele und elegante Familienstrategiespiele. Zu seinen bekanntesten Werken zählen Cartagena, Die verlorenen Städte und Carolus Magnus. Colovinis Spiele zeichnen sich durch einfache Regeln mit überraschender taktischer Tiefe aus.",
        "game_ids": ["432","1034","597","749","4828","4098","15742","12853","21133","23877","763","17392","17534","17808","4912","6298","10841","40973","55690","57167","60962","80011","92984","103641","129292","130484","135904","157637","180580","186102","188243","192748","198237","201672","207137","210399","215340","218100","225032","227968","228687","241220","243963","246340","247176","249324","252759","252831","254688","256949","257114","257142","269099","272657","281090","291073","302262","304005","304198","311166","313057","314890","316276","318419","321010","323506","324842","327032","329975","331239","333272","334827","339409","340745","341699","343811","344889","346235","346399","349499","353048","353173","356138","358411","360139","363624","367847","369195","369964","370079","371863","373434","373540","374137","374305","375489","376322","378831","379943","380514","380932","381502","381915","383964","384035","384864","385388","386243","387098","387625","388176","389130","389557","389878","391026","391626","392262","393815","394779","395013","396009","397501","398522","399347","399779","400148","400833","401097","401461","402027","402538","402936","403093","404955","405588","405797","406702","407228","407379","407647","408003","408241","410285","410979","411793","412086","412660","413016","413206","414369","414465","414608","415365","415544","415806","416244","416987","418019","418211","418852","418914","419027","419219","419590","420287","420329","421090","421697","421817","422447","422575","423382","423826","423970","424160","424443","425881","426198","426801","427050","427607","427685","428038","428610","429079","429626","429876","430033","430998","431136","431437","431954","431977","432736","432985","433014","434063","434393","435119","435542","435959","436474","436845","437263","437789","437929","438322","438358","439148","440187","440639","441027","441383","441424","441782","442094","442908","443211","443592","443727","444656","445479","445850","446705","447124","447206","447419","447677","447910","448189","448411","448676","449244","449281","449898","450458","450941","451326","451911","452519","452694","453218","454089","454327","454656","454857","455428","455624","455909","456441","456621","456696","457024","457497","457712","458536","458855","459027","459593","460154","460567","460785","461005","461433","461679","462572","462779","463003","463531","463823","464650","465128","465686","465900","466572","467348","467657","468324","468454","468823","469034","469792","470128","470460","470658","471288","471714","472182","473148","473245","474169","475336","476110"]
    }
}

# Which 10 to store tonight
# Pick: German/European + mix of classic and modern
TARGET_IDS = [
    "2",    # Reiner Knizia - German legend, hundreds of games
    "10",   # Uwe Rosenberg - German, Agricola
    "4958", # Stefan Feld - German, Castles of Burgundy
    "11767", # Alexander Pfister - Austrian, Great Western Trail
    "7",    # Wolfgang Kramer - German pioneer, 4x SdJ
    "9216", # Rüdiger Dorn - German, Goa
    "6045", # Mac Gerdts - German, Concordia
    "35418", # Simone Luciani - Italian, Grand Austria Hotel
    "1727", # Bruno Cathala - French, Kingdomino
    "9714", # Antoine Bauza - French, 7 Wonders
]

def main():
    print("=" * 60)
    print("BRETTSPIEL-AUTOREN-INVENTUR FÜR LETTA")
    print("12. Juni 2026 - 10 neue Autoren")
    print("=" * 60)

    stored = []
    skipped_existing = 0

    for did in TARGET_IDS:
        info = DESIGNER_GAMES[did]
        name = info["name"]
        print(f"\n{'─' * 50}")
        print(f"▶ AUTOR: {name} (BGG-ID: {did})")

        # 1. Check if already in Letta
        if is_already_stored(name, did):
            print(f"  ⏭ Bereits in Letta vorhanden — überspringe")
            skipped_existing += 1
            continue

        # 2. Fetch games from BGG to get real ranks
        print(f"  📡 Rufe BGG-Daten ab...")
        known_ids = info.get("game_ids", [])
        all_games, total = get_designer_games(name, did, known_ids)
        
        top5 = all_games[:5]
        top_str = ", ".join([f"{g['name']} (BGG #{g['rank']})" if g.get('rank') else g['name'] for g in top5])
        
        print(f"  ✅ {total} Spiele bestätigt, Top 5: {top_str}")

        # 3. Build and store the bio
        store_text = (
            f"AUTOR: {name} · BGG-ID: {did} · "
            f"Nationalität: {info['nationality']} · "
            f"Geburtsjahr: {info['year']} · "
            f"Biografie: {info['bio']} · "
            f"Bekannteste Spiele (Top 5): {top_str} · "
            f"Gesamtzahl veröffentlichter Spiele: {total} · "
            f"Charakteristische Mechaniken: {info['mechanisms']}"
        )

        try:
            result = store_in_letta(store_text)
            print(f"  ✅ In Letta gespeichert!")
            stored.append((name, top5[0] if top5 else None, top_str))
        except Exception as e:
            print(f"  ❌ Letta-Fehler: {e}")
        
        if len(stored) >= 10:
            break

    # 4. If we didn't get 10 (some were duplicates), add more
    if len(stored) < 10:
        # Add Michael Kiesling
        extra_ids = ["42", "138"]
        for did in extra_ids:
            if len(stored) >= 10:
                break
            info = DESIGNER_GAMES[did]
            name = info["name"]
            if is_already_stored(name, did):
                print(f"  ⏭ {name} bereits in Letta")
                continue
            known_ids = info.get("game_ids", [])
            all_games, total = get_designer_games(name, did, known_ids)
            top5 = all_games[:5]
            top_str = ", ".join([f"{g['name']} (BGG #{g['rank']})" if g.get('rank') else g['name'] for g in top5])
            store_text = (
                f"AUTOR: {name} · BGG-ID: {did} · "
                f"Nationalität: {info['nationality']} · "
                f"Geburtsjahr: {info['year']} · "
                f"Biografie: {info['bio']} · "
                f"Bekannteste Spiele (Top 5): {top_str} · "
                f"Gesamtzahl veröffentlichter Spiele: {total} · "
                f"Charakteristische Mechaniken: {info['mechanisms']}"
            )
            store_in_letta(store_text)
            stored.append((name, top5[0] if top5 else None, top_str))
            print(f"  ✅ {name} gespeichert")

    # 5. Verify what was stored
    print(f"\n\n{'=' * 60}")
    print(f"ERGEBNIS: {len(stored)} NEUE Autoren gespeichert (+ {skipped_existing} bereits vorhanden)")
    print(f"{'=' * 60}")
    
    for name, best, top_str in stored:
        if best:
            rank_str = f"BGG #{best['rank']}" if best.get('rank') else "BGG gelistet"
            print(f"  ✅ {name} — {best['name']} ({rank_str})")
        else:
            print(f"  ✅ {name}")
    
    print(f"\n📋 MORGENBERICHT:")
    for name, best, _ in stored:
        if best:
            r = f"BGG #{best['rank']}" if best.get('rank') else "BGG Top 200"
            print(f"- **{name}** ({best['name']}, {r})")
        else:
            print(f"- **{name}**")

if __name__ == "__main__":
    main()