#!/usr/bin/env python3
"""
Fantasywelt.de Vorbestellungs-Tracker
=====================================
Ermittelt alle Spiele, die in den letzten 30 Tagen neu ins Sortiment
gekommen und als Vorbestellung (nicht lieferbar) gelistet sind.

Nutzung:
  python3 fantasywelt_vorbestellungen.py              # Einmal-Ausführung
  python3 fantasywelt_vorbestellungen.py --days 30    # Zeitraum anpassen

Output:
  - HTML: /home/hermes/workspace/fantasywelt_data/vorbestellungen.html
  - Terminal: Zusammenfassung
"""

import csv, io, json, os, sys, urllib.request, urllib.error
from datetime import datetime, timedelta
from pathlib import Path
from html import escape

# ─── KONFIGURATION ───────────────────────────────────────────────────────────

CSV_URL = "https://www.fantasywelt.de/export/brettspiele.csv"
DATA_DIR = Path("/home/hermes/workspace/fantasywelt_data")
OUTPUT_FILE = DATA_DIR / "vorbestellungen.html"
AFFILIATE_TAG = "bsn=ig1UxQ0L2cNMNslzFhyr"
DEFAULT_DAYS = 30

# Aus dem Haupt-Tracker übernommene Filter
ZUBEHOER_KEYWORDS = [
    "schutzhüll", "sleeve", "hülle", "hüllen", "deckbox", "deck box", "deck-box",
    "schaumstoff", "feldherr", "portfolio", "zipfolio", "flexxfolio", "play-mat",
    "playmat", "play mat", "toploader", "card holder", "card divider",
    "pages ", "page ", "pocket pages", "kartenbox", "card case", "card box",
    "faltkarton", "lagerbox", "gaming case", "gaming box",
    "pro-matte", "pro-fit", "ultra pro", "ultra-snug",
    "dragon shield", "board game sleeves", "board games sleeves",
    "kmc small", "kmc standard", "precise-fit", "soft sleeves",
    "9-pocket", "4-pocket", "8-pocket", "12-pocket", "16-pocket", "18-pocket",
    "e-raptor spieler-tableau", "organizer", "würfel", "dice tower",
    "raster schaumstoff", "schaumstoffeinlage", "schaumstoffzuschnitt",
    "schaumstoff-set", "schaumstofeinlage", "schaumstoff abdeckung",
    "half-size schaumstoff", "full-size schaumstoff", "tasche für", "medium tasche",
    "miniatures pack", "playerboard", "game mat", "neoprene",
    "sammelalbum", "ultimate guard", "sidewinder", "omnihive", "xenoskin",
    "spielmatte", "playmat", "puzzle", "ausgrabung", "kristall",
    "farblabor", "experimentier", "deck protector", "boulder",
    "insert ", "insert für", "card backpack", "card case",
    "collector's edition small card", "collector's edition dnd",
    "enhance ", "backpack", "miniaturen-set", "miniaturen set",
    "miniatures set", "token set", "token kit", "acryl",
    "metallmünzen", "metal coins", "coin set", "münzset",
    "spielmünzen", "upgrade pack", "upgrade kit", "conversion kit",
    "bag of", "dice set", "würfelset", "würfel-set", "dice pack",
    "laserox", "insert", "inlay", "organizer", "einsatz",
]

EXCLUDE_KEYWORDS = ["mängelexemplar", "mängelexemplare", "mangelexemplar"]

# ─── HILFSFUNKTIONEN ─────────────────────────────────────────────────────────

def should_skip(name):
    n = name.lower()
    return any(kw in n for kw in ZUBEHOER_KEYWORDS) or any(kw in n for kw in EXCLUDE_KEYWORDS)

def add_affiliate(url):
    if not url:
        return url
    return url + ("&" if "?" in url else "?") + AFFILIATE_TAG

def download_csv():
    req = urllib.request.Request(CSV_URL, headers={"User-Agent": "BSN-Vorbestellungs-Tracker/1.0"})
    with urllib.request.urlopen(req, timeout=60) as resp:
        data = resp.read()
        try:
            return data.decode("utf-8")
        except UnicodeDecodeError:
            return data.decode("latin-1")

def parse_csv(raw):
    reader = csv.DictReader(io.StringIO(raw), delimiter=";", quotechar='"')
    products = []
    for row in reader:
        name = row.get("Name", "").strip()
        if not name:
            continue
        products.append({
            "name": name,
            "sku": row.get("Artikelnummer", "").strip(),
            "ean": row.get("EAN", "").strip(),
            "price": row.get("VK/Sonderpreis", "0").strip(),
            "available": row.get("Verfügbarkeit", "").strip(),
            "supply": row.get("Lieferstatus", "").strip(),
            "created": row.get("Erstellt am", "").strip(),
            "release": row.get("Erscheint am", "").strip(),
            "url": row.get("Produkt-URL", "").strip(),
            "image": row.get("Bild-URL", "").strip(),
            "bestprice": row.get("Best-Price_Garantie!", "N").strip(),
        })
    return products

def format_price(s):
    try:
        return f"{float(s.replace(',', '.')):.2f}".replace(".", ",")
    except:
        return s

def detect_language(name):
    n = name.upper()
    if "(DE|EN)" in n or "(DEEN)" in n or "(DE/EN)" in n:
        return "DE/EN"
    elif "(DE)" in n or "(DEUTSCH)" in n:
        return "DE"
    elif "(EN)" in n or "(ENGLISH)" in n or "(ENGLISCH)" in n:
        return "EN"
    elif "MULTILINGUAL" in n:
        return "Multi"
    return ""

def parse_date(s):
    """Parse YYYY-MM-DD oder YYYY-MM-DD HH:MM:SS"""
    s = s.strip()
    for fmt in ["%Y-%m-%d", "%Y-%m-%d %H:%M:%S"]:
        try:
            return datetime.strptime(s, fmt)
        except:
            continue
    return None

# ─── KERN-LOGIK ──────────────────────────────────────────────────────────────

def find_new_preorders(days=30):
    """Findet alle neuen Vorbestellungen der letzten N Tage."""
    cutoff = datetime.now() - timedelta(days=days)
    
    raw = download_csv()
    products = parse_csv(raw)
    
    vorbestellungen = []
    skipped_zubehoer = 0
    
    for p in products:
        # Nur Vorbestellungen
        if p["supply"] != "Vorbestellung":
            continue
        
        # Zubehör/Non-Games filtern
        if should_skip(p["name"]):
            skipped_zubehoer += 1
            continue
        
        # Erstellungsdatum prüfen
        created = parse_date(p["created"])
        if created is None or created < cutoff:
            continue
        
        # Release-Datum parsen
        release_dt = parse_date(p["release"]) if p["release"] else None
        release_str = release_dt.strftime("%d.%m.%Y") if release_dt else (p["release"] or "?")
        
        vorbestellungen.append({
            "name": p["name"],
            "price": p["price"],
            "url": p["url"],
            "image": p["image"],
            "created": created.strftime("%Y-%m-%d"),
            "release": release_str,
            "release_dt": release_dt,
            "bestprice": p["bestprice"],
        })
    
    # Sortieren: DE zuerst, dann nach Erstellungsdatum
    vorbestellungen.sort(key=lambda x: (
        detect_language(x["name"]) != "DE",
        detect_language(x["name"]) == "EN",
        x["created"]
    ))
    
    return vorbestellungen, skipped_zubehoer

# ─── HTML-GENERIERUNG ────────────────────────────────────────────────────────

def render_html(vorbestellungen, days):
    """Erzeugt eine saubere HTML-Übersicht im BSN-Stil."""
    
    if not vorbestellungen:
        return f"""<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fantasywelt Vorbestellungen – keine neuen Spiele</title>
<style>
  body {{ margin:0; padding:0; background:#f9f7f4; font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; color:#2c2416; line-height:1.75; }}
  article {{ max-width:720px; margin:0 auto; padding:3rem 1.5rem; background:#fff; box-shadow:0 2px 12px rgba(0,0,0,0.06); }}
</style>
</head>
<body><article>
<p style="color:#6b7280;text-align:center;padding:2rem 0;">Keine neuen Vorbestellungen in den letzten {days} Tagen.</p>
</article></body></html>"""
    
    rows = []
    for i, p in enumerate(vorbestellungen):
        name = escape(p["name"])
        price = format_price(p["price"])
        url = escape(add_affiliate(p["url"]))
        lang = detect_language(p["name"])
        release = p["release"]
        bestprice = p["bestprice"]
        
        # Badges
        badges = []
        if lang == "DE":
            badges.append('<span style="display:inline-block;background:#20228a;color:#fff;padding:1px 6px;border-radius:3px;font-size:0.7rem;margin-left:4px;">DE</span>')
        elif lang == "EN":
            badges.append('<span style="display:inline-block;background:#6b7280;color:#fff;padding:1px 6px;border-radius:3px;font-size:0.7rem;margin-left:4px;">EN</span>')
        elif lang == "Multi":
            badges.append('<span style="display:inline-block;background:#10b981;color:#fff;padding:1px 6px;border-radius:3px;font-size:0.7rem;margin-left:4px;">Multi</span>')
        
        if bestprice == "Y":
            badges.append('<span style="display:inline-block;background:#f59e0b;color:#fff;padding:1px 6px;border-radius:3px;font-size:0.7rem;margin-left:4px;">Best-Preis</span>')
        
        # Release-Datum prüfen (Zukunft = Warnung)
        release_badge = ""
        if p.get("release_dt") and p["release_dt"] > datetime.now():
            release_badge = f' <span style="display:inline-block;background:#dc3545;color:#fff;padding:1px 6px;border-radius:3px;font-size:0.7rem;margin-left:4px;">⚠ ET: {release}</span>'
        elif p.get("release_dt"):
            release_badge = f' <span style="display:inline-block;background:#e8e0d3;color:#5a4a3a;padding:1px 6px;border-radius:3px;font-size:0.7rem;margin-left:4px;">ET: {release}</span>'
        
        badge_html = "".join(badges)
        
        row = f"""<tr class="{'even' if i % 2 == 1 else ''}">
<td style="padding:0.6rem 0.7rem;border-bottom:1px solid #e8e0d3;">
  <a href="{url}" target="_blank" rel="sponsored" style="color:#c75b3a;font-weight:600;text-decoration:none;">{name}</a>
  {badge_html}{release_badge}
</td>
<td style="text-align:right;padding:0.6rem 0.7rem;border-bottom:1px solid #e8e0d3;white-space:nowrap;font-weight:700;color:#20228a;">{price} €</td>
<td style="text-align:center;padding:0.6rem 0.7rem;border-bottom:1px solid #e8e0d3;">
  <a href="{url}" target="_blank" rel="sponsored" style="display:inline-block;background:#20228a;color:#fff;text-decoration:none;padding:5px 14px;border-radius:99px;font-size:0.8rem;font-weight:700;white-space:nowrap;">Vorbestellen →</a>
</td>
</tr>"""
        rows.append(row)
    
    table_html = "\n".join(rows)
    
    de_count = sum(1 for p in vorbestellungen if detect_language(p["name"]) == "DE")
    en_count = sum(1 for p in vorbestellungen if detect_language(p["name"]) == "EN")
    multi_count = sum(1 for p in vorbestellungen if detect_language(p["name"]) in ("Multi", "DE/EN"))
    
    return f"""<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fantasywelt Vorbestellungen – Neue Spiele der letzten {days} Tage</title>
<style>
  body {{ margin:0; padding:0; background:#f9f7f4; font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; color:#2c2416; line-height:1.75; }}
  article {{ max-width:720px; margin:0 auto; padding:2rem 1.5rem; background:#fff; box-shadow:0 2px 12px rgba(0,0,0,0.06); }}
  h1 {{ font-size:1.5rem; margin-top:0; color:#1a1a1a; }}
  h2 {{ font-size:1.2rem; margin:1.5rem 0 0.75rem; color:#333; border-bottom:2px solid #e8e0d3; padding-bottom:0.3rem; }}
  .stats {{ display:flex; gap:1rem; flex-wrap:wrap; margin:1rem 0 1.5rem; }}
  .stat {{ background:#f0ebe0; border-radius:8px; padding:0.4rem 1rem; font-size:0.85rem; }}
  .stat strong {{ color:#20228a; }}
  table {{ width:100%; border-collapse:collapse; margin:1rem 0; font-size:0.9rem; }}
  th {{ background:#f0ebe0; text-align:left; padding:0.5rem 0.7rem; border-bottom:2px solid #d5c9b3; font-weight:600; }}
  th:last-child {{ text-align:center; }}
  tr.even td {{ background:#faf7f2; }}
  .qc {{ font-size:0.75rem; color:#aaa; margin-top:2rem; border-top:1px solid #e8e0d3; padding-top:0.8rem; }}
  @media (max-width:500px) {{
    article {{ padding:1rem 0.7rem; }}
    td, th {{ font-size:0.8rem; padding:0.4rem; }}
  }}
</style>
</head>
<body>
<article>

<h1>🎯 Neue Vorbestellungen bei Fantasywelt</h1>
<p style="color:#6b7280;font-size:0.85rem;margin-bottom:1.5rem;">
  Folgende Brett- und Kartenspiele sind in den letzten {days} Tagen neu ins Fantasywelt-Sortiment aufgenommen worden 
  und aktuell als <strong>Vorbestellung</strong> gelistet (nicht sofort lieferbar).
  Stand: {datetime.now().strftime('%d.%m.%Y')}
</p>

<div class="stats">
  <div class="stat">Gesamt: <strong>{len(vorbestellungen)}</strong></div>
  <div class="stat">🇩🇪 DE: <strong>{de_count}</strong></div>
  <div class="stat">🇬🇧 EN: <strong>{en_count}</strong></div>
  <div class="stat">🌐 Multi: <strong>{multi_count}</strong></div>
</div>

<table>
<thead>
<tr><th>Spiel</th><th style="text-align:right;">Preis</th><th style="text-align:center;"></th></tr>
</thead>
<tbody>
{table_html}
</tbody>
</table>

<p class="qc">Alle Preise inkl. MwSt. · Links sind Affiliate-Links (bsn=ig1UxQ0L2cNMNslzFhyr) · Datenquelle: <a href="https://www.fantasywelt.de/export/brettspiele.csv">Fantasywelt CSV-Export</a></p>

</article>
</body>
</html>"""

# ─── MAIN ────────────────────────────────────────────────────────────────────

def build_article_html(vorbestellungen):
    """Baut den kompletten Joomla-Artikel mit ALLEN Vorbestellungen."""
    from html import escape as esc
    
    rows = []
    for p in vorbestellungen:
        name = esc(p["name"])
        price = format_price(p["price"])
        url = esc(add_affiliate(p["url"]))
        lang = detect_language(p["name"])
        release = p["release"]
        
        badges = ''
        if lang == 'DE':
            badges += '<span style="display:inline-block;background:#20228a;color:#fff;padding:1px 6px;border-radius:3px;font-size:0.7rem;margin-left:4px;">DE</span>'
        elif lang == 'EN':
            badges += '<span style="display:inline-block;background:#6b7280;color:#fff;padding:1px 6px;border-radius:3px;font-size:0.7rem;margin-left:4px;">EN</span>'
        elif lang in ('Multi','DE/EN'):
            badges += '<span style="display:inline-block;background:#10b981;color:#fff;padding:1px 6px;border-radius:3px;font-size:0.7rem;margin-left:4px;">Multi</span>'
        
        if p["bestprice"] == "Y":
            badges += '<span style="display:inline-block;background:#f59e0b;color:#fff;padding:1px 6px;border-radius:3px;font-size:0.7rem;margin-left:4px;">Best-Preis</span>'
        
        et_badge = ''
        if p.get("release_dt") and p["release_dt"] > datetime.now():
            et_badge = f' <span style="display:inline-block;background:#dc3545;color:#fff;padding:1px 6px;border-radius:3px;font-size:0.7rem;margin-left:4px;">⚠ ET: {release}</span>'
        elif p.get("release_dt"):
            et_badge = f' <span style="display:inline-block;background:#e8e0d3;color:#5a4a3a;padding:1px 6px;border-radius:3px;font-size:0.7rem;margin-left:4px;">ET: {release}</span>'
        
        row = f'''<tr>
<td style="padding:0.5rem 0.7rem;border-bottom:1px solid #e8e0d3;">
  <a href="{url}" target="_blank" rel="sponsored" style="color:#c75b3a;font-weight:600;">{name}</a>
  {badges}{et_badge}
</td>
<td style="text-align:right;padding:0.5rem 0.7rem;border-bottom:1px solid #e8e0d3;white-space:nowrap;font-weight:700;color:#20228a;">{price} €</td>
<td style="text-align:center;padding:0.5rem 0.7rem;border-bottom:1px solid #e8e0d3;">
  <a href="{url}" target="_blank" rel="sponsored" style="display:inline-block;background:#20228a;color:#fff;text-decoration:none;padding:4px 12px;border-radius:99px;font-size:0.8rem;font-weight:700;">Vorbestellen →</a>
</td>
</tr>'''
        rows.append(row)
    
    table = '\n'.join(rows)
    de_count = sum(1 for p in vorbestellungen if detect_language(p["name"]) == "DE")
    en_count = sum(1 for p in vorbestellungen if detect_language(p["name"]) == "EN")
    multi_count = len(vorbestellungen) - de_count - en_count
    heute = datetime.now().strftime("%d.%m.%Y")
    kw = datetime.now().isocalendar()[1]
    
    return f'''<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{len(vorbestellungen)} neue Brett- und Kartenspiele sind in den letzten 30 Tagen bei Fantasywelt als Vorbestellung gelistet. Alle Preise, Erscheinungstermine und Direktlinks.">
<meta name="keywords" content="Fantasywelt, Vorbestellungen, Brettspiele, Neuerscheinungen, Preorder">
<meta name="joomla-id" content="15378">
<title>Fantasywelt Vorbestellungen: {len(vorbestellungen)} neue Spiele vorbestellbar (KW {kw})</title>
<style>
  body {{ margin: 0; padding: 0; background: #f9f7f4; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; color: #2c2416; line-height: 1.75; }}
  article {{ max-width: 720px; margin: 0 auto; padding: 2rem 1.5rem; background: #fff; box-shadow: 0 2px 12px rgba(0,0,0,0.06); }}
  h1 {{ font-size: 1.6rem; margin-top: 0; color: #1a1a1a; }}
  p {{ margin: 0 0 1rem; }}
  a {{ color: #c75b3a; text-decoration: none; }}
  a:hover {{ text-decoration: underline; }}
  .meta {{ color: #999; font-size: 0.85rem; margin-bottom: 2rem; }}
  .stats {{ display: flex; gap: 1rem; flex-wrap: wrap; margin: 1rem 0 1.5rem; }}
  .stat {{ background: #f0ebe0; border-radius: 8px; padding: 0.4rem 1rem; font-size: 0.85rem; }}
  .stat strong {{ color: #20228a; }}
  table {{ width: 100%; border-collapse: collapse; margin: 1rem 0; font-size: 0.9rem; }}
  th {{ background: #f0ebe0; text-align: left; padding: 0.5rem 0.7rem; border-bottom: 2px solid #d5c9b3; font-weight: 600; }}
  td {{ padding: 0.5rem 0.7rem; border-bottom: 1px solid #e8e0d3; }}
  tr:nth-child(even) td {{ background: #faf7f2; }}
  .qc {{ font-size: 0.75rem; color: #aaa; margin-top: 2rem; border-top: 1px solid #e8e0d3; padding-top: 0.8rem; }}
  @media (max-width: 500px) {{
    article {{ padding: 0.8rem 0.5rem; }}
    td, th {{ font-size: 0.78rem; padding: 0.35rem; }}
  }}
</style>
</head>
<body>
<article>

<h1>Fantasywelt Vorbestellungen: {len(vorbestellungen)} neue Spiele vorbestellbar (KW {kw})</h1>
<p class="meta">{heute} · Vorbestellungen · Automatisiert</p>

<p>In den letzten 30 Tagen hat Fantasywelt {len(vorbestellungen)} neue Brett- und Kartenspiele ins Sortiment aufgenommen, die aktuell ausschließlich als <strong>Vorbestellung</strong> gelistet sind — also nicht sofort lieferbar, aber reservierbar.</p>

<hr id="system-readmore" />

<div class="stats">
  <div class="stat">Gesamt: <strong>{len(vorbestellungen)}</strong></div>
  <div class="stat">🇩🇪 DE: <strong>{de_count}</strong></div>
  <div class="stat">🇬🇧 EN: <strong>{en_count}</strong></div>
  <div class="stat">🌐 Multi: <strong>{multi_count}</strong></div>
</div>

<table>
<thead>
<tr><th>Spiel</th><th style="text-align:right;">Preis</th><th style="text-align:center;"></th></tr>
</thead>
<tbody>
{table}
</tbody>
</table>

<p class="qc">QC: ✅ {len(vorbestellungen)} Vorbestellungen via CSV-Export · ✅ Zubehör/Non-Games ausgefiltert · ✅ Affiliate-Links (bsn=ig1UxQ0L2cNMNslzFhyr) · ✅ Automatisiert jeden Freitag</p>

</article>
</body>
</html>'''


def publish_article(html_content, article_filename="artikel_fantasywelt_vorbestellungen_auto.html"):
    """Sendet den Artikel-HTML an den Article-Server (localhost:8890/publish)."""
    import urllib.request, base64, json as _json
    
    article_path = DATA_DIR.parent / article_filename
    with open(article_path, "w", encoding="utf-8") as f:
        f.write(html_content)
    
    auth = base64.b64encode(b"DK-Adminchef:Mcik7%vbdhXa_").decode()
    payload = _json.dumps({"files": [article_filename], "live": False}).encode()
    
    req = urllib.request.Request(
        f"http://localhost:8890/publish?key=br3ttsp1el-n3ws-2026",
        data=payload,
        headers={
            "Authorization": f"Basic {auth}",
            "Content-Type": "application/json",
        },
        method="POST"
    )
    
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            result = _json.loads(resp.read())
        return result
    except Exception as e:
        return {"ok": False, "error": str(e)}


def main():
    import argparse
    parser = argparse.ArgumentParser(description="Fantasywelt Vorbestellungs-Tracker")
    parser.add_argument("--days", type=int, default=DEFAULT_DAYS)
    parser.add_argument("--publish-article", action="store_true")
    args = parser.parse_args()
    days = args.days
    
    print(f"🔍 Suche neue Vorbestellungen der letzten {days} Tage...")
    
    vorbestellungen, skipped = find_new_preorders(days)
    
    print(f"✅ {len(vorbestellungen)} neue vorbestellbare Spiele gefunden")
    print(f"🚫 {skipped} Zubehör-Artikel ausgefiltert")
    print()
    
    # Kurzübersicht für Terminal
    de_games = [p for p in vorbestellungen if detect_language(p["name"]) == "DE"]
    en_games = [p for p in vorbestellungen if detect_language(p["name"]) == "EN"]
    
    if de_games:
        print(f"─── DE-Vorbestellungen ({len(de_games)}) ───")
        for p in de_games[:15]:
            print(f"  {p['name'][:60]} | {format_price(p['price'])} € | ET: {p['release']}")
        if len(de_games) > 15:
            print(f"  ... und {len(de_games) - 15} weitere")
    
    if en_games:
        print(f"\n─── EN-Vorbestellungen ({len(en_games)}) ───")
        for p in en_games[:5]:
            print(f"  {p['name'][:60]} | {format_price(p['price'])} € | ET: {p['release']}")
        if len(en_games) > 5:
            print(f"  ... und {len(en_games) - 5} weitere")
    
    # HTML-Übersicht (immer)
    html = render_html(vorbestellungen, days)
    DATA_DIR.mkdir(parents=True, exist_ok=True)
    with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
        f.write(html)
    print(f"\n📄 HTML-Übersicht: {OUTPUT_FILE}")
    
    # Joomla-Artikel publizieren
    if args.publish_article:
        print("\n📰 Baue kompletten Artikel mit allen Spielen...")
        article_html = build_article_html(vorbestellungen)
        result = publish_article(article_html)
        if result.get("ok"):
            print(f"✅ Artikel 15378 aktualisiert ({len(vorbestellungen)} Spiele)")
            if result.get("errors"):
                for e in result["errors"]:
                    print(f"  ⚠️ {e}")
        else:
            print(f"❌ Fehler: {result.get('error', 'unbekannt')}")
    else:
        print(f"🌐 http://185.162.249.159:8890/fantasywelt_data/vorbestellungen.html?key=br3ttsp1el-n3ws-2026")


if __name__ == "__main__":
    main()
