#!/usr/bin/env python3
"""Fetch Amazon board game deals and compare with brettspielpreise.de price histories.
Final version with validated matches."""

import re, json, time, urllib.request, urllib.parse, ssl

# ---- Step 1: Parse HTML ----
html_path = "/home/hermes/workspace/amazon_deals_2026-06-05.html"
with open(html_path, "r", encoding="utf-8") as f:
    html = f.read()

deal_blocks = re.findall(
    r'<div style="display:flex;gap:1rem;padding:1rem 0;border-bottom:1px solid #eee;">'
    r'(.*?)</div></div>',
    html, re.DOTALL
)
print(f"Found {len(deal_blocks)} deal blocks")

deals = []
for block in deal_blocks:
    name_match = re.search(r'<strong>(.*?)</strong>', block)
    name = name_match.group(1).strip() if name_match else "Unknown"
    price_match = re.search(r'font-weight:bold;">(\d+[.,]\d+) €', block)
    price = float(price_match.group(1).replace(",", ".")) if price_match else None
    uvp_match = re.search(r'UVP (\d+[.,]\d+) €', block)
    uvp = float(uvp_match.group(1).replace(",", ".")) if uvp_match else None
    asin_match = re.search(r'/dp/([A-Z0-9]+)', block)
    asin = asin_match.group(1) if asin_match else None
    url_match = re.search(r'href="(https://www\.amazon\.de/dp/[^"]+)"', block)
    url = url_match.group(1) if url_match else f"https://www.amazon.de/dp/{asin}?tag=60pro05-21"
    deals.append({"name": name, "amazon_price": price, "uvp": uvp, "asin": asin, "url": url})

# ---- Step 2: Filter ----
FILTER_KEYWORDS = [
    "schwarzer peter", "skat", "rommé", "romme", "bridge canasta",
    "top trumps", "wetfussballstars",
    "uno ", "uno flip", "uno show", "uno teams", "phase 10",
]

filtered = []
for d in deals:
    name_lower = d["name"].lower()
    if not any(kw in name_lower for kw in FILTER_KEYWORDS):
        filtered.append(d)
    else:
        kw = next(kw for kw in FILTER_KEYWORDS if kw in name_lower)
        print(f"  SKIP: {d['name'][:70]}...  [{kw}]")

print(f"After filtering: {len(filtered)} deals")

# ---- Step 3: HTTP helpers ----
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

def http_get(url):
    req = urllib.request.Request(url, headers={
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36",
    })
    try:
        with urllib.request.urlopen(req, timeout=15, context=ctx) as resp:
            return resp.read().decode("utf-8", errors="replace")
    except Exception:
        return None

# ---- Search terms with specific overrides ----
SEARCH_CONFIG = [
    # (amazon_name_keyword, search_term)
    ("Maus reiß aus", "Maus reiß aus"),
    ("Die Verräter", "Die Verräter Brettspiel"),
    ("Jumanji", "Jumanji Familienspiel"),
    ("Monsterjäger", "Monsterjäger Schmidt"),
    ("Sweet Takes", "Sweet Takes"),
    ("My City", "My City Kosmos"),
    ("Evacuation", "Evacuation"),
    ("STILLE POST EXTREM", "Stille Post Extrem"),
    ("Dog", "Dog Royal"),
    ("THE MIND", "The Mind"),
    ("Catan", "Catan"),
    ("Leben in Reterra", "Leben in Reterra"),
    ("Sagaland", "Sagaland"),
    ("Hitster", "Hitster"),
    ("Outsmarted", "Outsmarted"),
    ("Monopoly Harry Potter", "Monopoly Harry Potter"),
    ("Die Magischen Schlüssel", "Die Magischen Schlüssel"),
    ("Scrabble Zwei in Eins", "Scrabble"),
    ("Das verrückte Labyrinth", "Das verrückte Labyrinth"),
    ("Funkelschatz", "Funkelschatz"),
    ("Leiterspiel", "Leiterspiel Schmidt"),
    ("Ligretto", "Ligretto"),
]

FALLBACK_SEARCH = {
    "Die Verräter": ["the traitors die verrater"],
    "Dog": ["Dog Den letzten beissen die Hunde"],
    "Sweet Takes": ["Sweet Takes Hasbro"],
    "Die Magischen Schlüssel": ["Magischen Schlüssel Game Factory"],
}

def get_search_terms(name):
    terms = []
    for key, val in SEARCH_CONFIG:
        if key.lower() in name.lower():
            terms.append(val)
            break
    if not terms:
        words = name.replace("-", " ").replace("–", " ").replace(",", " ").split()
        stop = {"das", "die", "der", "den", "für", "und", "mit", "von", "ein", "eine", "einen", "ab", "des", "dem"}
        meaningful = [w for w in words if w.lower() not in stop and len(w) > 1 and not w.isdigit()]
        terms.append(" ".join(meaningful[:3]))
    
    for key, fbs in FALLBACK_SEARCH.items():
        if key.lower() in name.lower():
            for fb in fbs:
                if fb not in terms:
                    terms.append(fb)
    return terms

def search_brettspielpreise(search_term):
    url = f"https://brettspielpreise.de/item/search?search={urllib.parse.quote(search_term)}"
    body = http_get(url)
    if not body:
        return []
    show_links = re.findall(r'/item/show/(\d+)/([^"]+)', body)
    items, seen = [], set()
    for item_id, slug in show_links:
        if item_id not in seen:
            seen.add(item_id)
            history_url = f"https://brettspielpreise.de/item/history/{item_id}/{slug}"
            items.append((item_id, urllib.parse.unquote(slug), history_url))
    return items[:5]

def get_price_history(history_url):
    body = http_get(history_url)
    if not body:
        return None
    idx = body.find('datasets')
    if idx == -1:
        return None
    s = body.rfind('<script', 0, idx)
    e = body.find('</script>', idx)
    if s == -1 or e == -1:
        return None
    script = body[s:e]
    all_data, pos = [], 0
    while True:
        di = script.find('data: [', pos)
        if di == -1:
            break
        start = di + 6
        depth, end = 0, start
        for i in range(start, len(script)):
            if script[i] == '[':
                depth += 1
            elif script[i] == ']':
                depth -= 1
                if depth == 0:
                    end = i + 1
                    break
        try:
            pts = json.loads(script[start:end])
            all_data.append(pts)
        except json.JSONDecodeError:
            pass
        pos = end
    for pts in all_data:
        if pts and isinstance(pts, list) and len(pts) > 0 and isinstance(pts[0], dict) and "y" in pts[0]:
            prices = []
            for pt in pts:
                try:
                    p = float(pt.get("y", 0))
                    if p > 0:
                        prices.append(p)
                except (ValueError, TypeError):
                    pass
            if len(prices) >= 3:
                return prices
    return None

def validate_match(current, low, high, datapoints):
    """Check if current price reasonably fits this game's history."""
    if low <= 0:
        return False
    dist = (current - low) / low * 100
    
    # For sparse data (<15 points), allow wider range (tracking may miss deals)
    if datapoints < 15:
        if dist < -65:  # very sparse data could miss deals entirely
            return False
    else:
        if dist < -35:  # current shouldn't be way below tracked history
            return False
    
    if dist > 300:  # way too expensive = wrong match
        return False
    
    return True

# ---- Step 4: Process ----
results = []
skipped_wrong_match = []

for i, d in enumerate(filtered):
    print(f"\n[{i+1}/{len(filtered)}] {d['name'][:75]}")
    print(f"    Amazon: {d['amazon_price']}€ | UVP: {d['uvp']}€")
    
    search_terms = get_search_terms(d["name"])
    matched = False
    
    for term in search_terms:
        if matched:
            break
        candidates = search_brettspielpreise(term)
        if not candidates:
            continue
        
        for c_idx, (item_id, item_name, history_url) in enumerate(candidates):
            prices = get_price_history(history_url)
            if not prices:
                continue
            
            low, high = round(min(prices), 2), round(max(prices), 2)
            current = d["amazon_price"]
            
            if not validate_match(current, low, high, len(prices)):
                dist = (current - low) / low * 100
                print(f"      #{c_idx+1} ID {item_id} '{item_name[:45]}': low={low}€, dist={dist:.1f}% → SKIP")
                continue
            
            dist_pct = round((current - low) / low * 100, 1)
            sav_pct = round((d["uvp"] - current) / d["uvp"] * 100, 1) if d["uvp"] and d["uvp"] > 0 else 0
            
            print(f"    ✓ MATCH: '{item_name[:50]}' (ID {item_id})")
            print(f"      History: {len(prices)}pts, low={low}€, high={high}€, current={current}€ ({dist_pct:+.1f}%)")
            
            results.append({
                "name": d["name"],
                "amazon_price": current,
                "uvp": d["uvp"],
                "savings_pct": sav_pct,
                "history_low": low,
                "history_high": high,
                "distance_from_low_pct": dist_pct,
                "url": d["url"],
                "history_url": history_url,
                "datapoints": len(prices),
            })
            matched = True
            break
    
    if not matched:
        print(f"    ✗ No valid match on brettspielpreise.de")

# Sort: closer to best price first (lowest distance_from_low_pct)
results.sort(key=lambda x: x["distance_from_low_pct"])

print(f"\n{'='*70}")
print(f"RESULTS: {len(results)} games with price histories (sorted by proximity to best price)")
print(f"{'='*70}")
for i, r in enumerate(results):
    star = "⭐" if r["distance_from_low_pct"] <= 10 else "  "
    print(f"  {i+1:2d}. {star} {r['distance_from_low_pct']:>+6.1f}% | {r['amazon_price']:>7.2f}€ "
          f"(low: {r['history_low']:>6.2f}€, high: {r['history_high']:>6.2f}€, {r['datapoints']}pts) "
          f"| {r['name'][:50]}")

# Save JSON
output_path = "/tmp/amazon_near_bestprice.json"
with open(output_path, "w", encoding="utf-8") as f:
    json.dump(results, f, ensure_ascii=False, indent=2)
print(f"\nSaved {len(results)} results to {output_path}")

# Summary stats
close = [r for r in results if r["distance_from_low_pct"] <= 15]
print(f"\n⭐ {len(close)} games within 15% of their historical best price")
print(f"   {len([r for r in results if r['distance_from_low_pct'] <= 0])} games at or below historical best price (new lows!)")
