#!/usr/bin/env python3
"""Fix Notion Inspiration Library covers across 3 categories."""

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

API_KEY = open("/home/clawd/secrets/notion/api_key").read().strip()
DB_ID = "2ff330c2-8646-81f0-bbd9-ec474393d7a5"
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Notion-Version": "2022-06-28",
    "Content-Type": "application/json",
}
SSL_CTX = ssl._create_unverified_context()
RATE = 0.35

def notion_req(method, url, data=None):
    time.sleep(RATE)
    body = json.dumps(data).encode() if data else None
    req = urllib.request.Request(url, data=body, headers=HEADERS, method=method)
    with urllib.request.urlopen(req) as r:
        return json.loads(r.read())

def get_all_pages():
    pages = []
    cursor = None
    while True:
        payload = {"page_size": 100}
        if cursor:
            payload["start_cursor"] = cursor
        resp = notion_req("POST", f"https://api.notion.com/v1/databases/{DB_ID}/query", payload)
        for p in resp["results"]:
            if not p.get("cover"):
                pages.append(p)
        if not resp.get("has_more"):
            break
        cursor = resp["next_cursor"]
    return pages

def get_title(page):
    for v in page.get("properties", {}).values():
        if v.get("type") == "title":
            return "".join(t.get("plain_text", "") for t in v.get("title", []))
    return "(untitled)"

def get_url(page):
    for v in page.get("properties", {}).values():
        if v.get("type") == "url":
            return v.get("url") or ""
    return ""

def fetch_og_image(url):
    patterns = [
        r'<meta\s+property=["\']og:image["\']\s+content=["\']([^"\']+)["\']',
        r'<meta\s+content=["\']([^"\']+)["\']\s+property=["\']og:image["\']',
        r'og:image["\']\s*content=["\']([^"\']+)["\']',
    ]
    req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
    try:
        with urllib.request.urlopen(req, timeout=10, context=SSL_CTX) as r:
            html = r.read(200000).decode("utf-8", errors="ignore")
    except Exception:
        return None
    for pat in patterns:
        m = re.search(pat, html, re.IGNORECASE)
        if m:
            img = m.group(1)
            if img.startswith("http"):
                return img
    return None

def set_cover(page_id, image_url):
    notion_req("PATCH", f"https://api.notion.com/v1/pages/{page_id}", {
        "cover": {"type": "external", "external": {"url": image_url}}
    })

def get_first_image_block(page_id):
    try:
        resp = notion_req("GET", f"https://api.notion.com/v1/blocks/{page_id}/children?page_size=50")
    except Exception:
        return None
    for b in resp.get("results", []):
        if b.get("type") == "image":
            img = b.get("image", {})
            if img.get("type") == "file":
                return img["file"]["url"]
            elif img.get("type") == "external":
                return img["external"]["url"]
    return None

def main():
    print("Fetching all pages without covers...")
    pages = get_all_pages()
    print(f"Found {len(pages)} pages without covers")

    cat1, cat2, cat3 = [], [], []
    for p in pages:
        url = get_url(p)
        title = get_title(p)
        if url:
            cat1.append(p)
        elif re.search(r'\.[a-z]{3,4}$', title.lower()) and not title.startswith("http"):
            cat2.append(p)
        else:
            cat3.append(p)

    print(f"Cat1 (URL→og:image): {len(cat1)}")
    print(f"Cat2 (image filename, no URL): {len(cat2)}")
    print(f"Cat3 (other, no URL): {len(cat3)}")

    stats = {k: 0 for k in ["c1_set","c1_skip","c2_set","c2_skip","c3_set","c3_skip"]}

    # Category 1: fetch og:image from URL
    for i, p in enumerate(cat1, 1):
        title = get_title(p)
        url = get_url(p)
        try:
            og = fetch_og_image(url)
            if og:
                set_cover(p["id"], og)
                print(f"[cat1 {i}/{len(cat1)}] Set cover for \"{title}\" → {og[:80]}")
                stats["c1_set"] += 1
            else:
                print(f"[cat1 {i}/{len(cat1)}] Skip \"{title}\" — no og:image")
                stats["c1_skip"] += 1
        except Exception as e:
            print(f"[cat1 {i}/{len(cat1)}] Error \"{title}\" — {e}")
            stats["c1_skip"] += 1

    # Category 2 & 3: check for image blocks in children
    for cat_name, cat_list, set_key, skip_key in [("cat2", cat2, "c2_set", "c2_skip"), ("cat3", cat3, "c3_set", "c3_skip")]:
        for i, p in enumerate(cat_list, 1):
            title = get_title(p)
            try:
                img_url = get_first_image_block(p["id"])
                if img_url:
                    set_cover(p["id"], img_url)
                    print(f"[{cat_name} {i}/{len(cat_list)}] Set cover for \"{title}\"")
                    stats[set_key] += 1
                else:
                    print(f"[{cat_name} {i}/{len(cat_list)}] Skip \"{title}\" — no image block")
                    stats[skip_key] += 1
            except Exception as e:
                print(f"[{cat_name} {i}/{len(cat_list)}] Error \"{title}\" — {e}")
                stats[skip_key] += 1

    total_set = stats["c1_set"] + stats["c2_set"] + stats["c3_set"]
    total_skip = stats["c1_skip"] + stats["c2_skip"] + stats["c3_skip"]
    print(f"\n{'='*50}")
    print(f"SUMMARY")
    print(f"Cat1 (URL→og:image): {stats['c1_set']} set, {stats['c1_skip']} skipped")
    print(f"Cat2 (image files):   {stats['c2_set']} set, {stats['c2_skip']} skipped")
    print(f"Cat3 (other/tagged):  {stats['c3_set']} set, {stats['c3_skip']} skipped")
    print(f"TOTAL: {total_set} covers set, {total_skip} skipped")
    print(f"\nNote: Cat2/Cat3 pages with no image blocks have files as page titles only —")
    print(f"the actual images are not stored as Notion blocks and cannot be set as covers via API.")

if __name__ == "__main__":
    main()
