#!/usr/bin/env python3
"""Recover images for Notion Inspiration Library entries."""

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

NOTION_KEY = open("/home/clawd/secrets/notion/api_key").read().strip()
DB_ID = "2ff330c2-8646-81f0-bbd9-ec474393d7a5"
HEADERS = {
    "Authorization": f"Bearer {NOTION_KEY}",
    "Notion-Version": "2022-06-28",
    "Content-Type": "application/json",
}
SSL_CTX = ssl._create_unverified_context()
BEHANCE_RE = re.compile(r'^[a-f0-9]+\.[a-f0-9]+\.(jpg|jpeg|png|gif|webp)$')

def notion_req(method, url, data=None):
    time.sleep(0.35)
    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 fetch_all_pages():
    pages = []
    url = f"https://api.notion.com/v1/databases/{DB_ID}/query"
    has_more = True
    cursor = None
    while has_more:
        body = {"page_size": 100}
        if cursor:
            body["start_cursor"] = cursor
        resp = notion_req("POST", url, body)
        pages.extend(resp["results"])
        has_more = resp.get("has_more", False)
        cursor = resp.get("next_cursor")
    return pages

def get_title(page):
    for prop in page["properties"].values():
        if prop["type"] == "title" and prop["title"]:
            return "".join(t["plain_text"] for t in prop["title"])
    return ""

def get_link(page):
    for prop in page["properties"].values():
        if prop["type"] == "url" and prop.get("url"):
            return prop["url"]
    return ""

def has_cover(page):
    return page.get("cover") is not None

def get_tags(page):
    for prop in page["properties"].values():
        if prop["type"] == "multi_select":
            return [t["name"] for t in prop["multi_select"]]
    return []

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

def add_tag(page_id, existing_tags, new_tag):
    tags = [{"name": t} for t in existing_tags]
    if new_tag not in existing_tags:
        tags.append({"name": new_tag})
    # Find the multi_select property name
    notion_req("PATCH", f"https://api.notion.com/v1/pages/{page_id}", {
        "properties": {"Tags": {"multi_select": tags}}
    })

def head_ok(url):
    try:
        req = urllib.request.Request(url, method="HEAD", headers={"User-Agent": "Mozilla/5.0"})
        with urllib.request.urlopen(req, context=SSL_CTX, timeout=10) as r:
            return r.status == 200
    except:
        return False

def get_og_image(url):
    try:
        time.sleep(1)
        req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"})
        with urllib.request.urlopen(req, context=SSL_CTX, timeout=10) as r:
            html = r.read(500000).decode("utf-8", errors="ignore")
        for pattern in [
            r'<meta\s+property=["\']og:image["\']\s+content=["\']([^"\']+)["\']',
            r'<meta\s+content=["\']([^"\']+)["\']\s+property=["\']og:image["\']',
            r'<meta\s+property=["\']twitter:image["\']\s+content=["\']([^"\']+)["\']',
            r'<meta\s+content=["\']([^"\']+)["\']\s+property=["\']twitter:image["\']',
            r'<meta\s+name=["\']twitter:image["\']\s+content=["\']([^"\']+)["\']',
            r'<meta\s+content=["\']([^"\']+)["\']\s+name=["\']twitter:image["\']',
        ]:
            m = re.search(pattern, html, re.IGNORECASE)
            if m and m.group(1).startswith("http"):
                return m.group(1)
    except:
        pass
    return None

def main():
    print("Fetching all pages...")
    pages = fetch_all_pages()
    print(f"Total pages: {len(pages)}")

    stats = {"p1_ok": 0, "p1_skip": 0, "p2_ok": 0, "p2_skip": 0, "p3_ok": 0, "p3_skip": 0, "p4_ok": 0}

    # Part 1: Behance
    print("\n=== Part 1: Behance filename recovery ===")
    behance = [p for p in pages if not has_cover(p) and not get_link(p) and BEHANCE_RE.match(get_title(p))]
    print(f"Found {len(behance)} Behance orphans")
    for i, p in enumerate(behance, 1):
        try:
            title = get_title(p)
            for base in ["max_1200", "1400"]:
                url = f"https://mir-s3-cdn-cf.behance.net/project_modules/{base}/{title}"
                if head_ok(url):
                    set_cover(p["id"], url)
                    print(f"[Part1 {i}/{len(behance)}] Set cover for \"{title}\" → {url}")
                    stats["p1_ok"] += 1
                    break
            else:
                print(f"[Part1 {i}/{len(behance)}] Skip \"{title}\" — not found")
                stats["p1_skip"] += 1
        except Exception as e:
            print(f"[Part1 {i}/{len(behance)}] Error \"{get_title(p)}\": {e}")
            stats["p1_skip"] += 1

    # Part 2: OG image for URL entries without covers
    print("\n=== Part 2: OG image capture ===")
    url_no_cover = [p for p in pages if not has_cover(p) and get_link(p)]
    print(f"Found {len(url_no_cover)} URL entries without covers")
    for i, p in enumerate(url_no_cover, 1):
        try:
            title = get_title(p)
            link = get_link(p)
            og = get_og_image(link)
            if og:
                set_cover(p["id"], og)
                print(f"[Part2 {i}/{len(url_no_cover)}] Set cover for \"{title}\" → {og[:80]}")
                stats["p2_ok"] += 1
            else:
                print(f"[Part2 {i}/{len(url_no_cover)}] Skip \"{title}\" — no og:image")
                stats["p2_skip"] += 1
        except Exception as e:
            print(f"[Part2 {i}/{len(url_no_cover)}] Error \"{get_title(p)}\": {e}")
            stats["p2_skip"] += 1

    # Part 3: Add missing CSV entries
    print("\n=== Part 3: Add missing CSV entries ===")
    existing_urls = {get_link(p) for p in pages if get_link(p)}
    csv_path = "/root/.openclaw/media/inbound/99031230-4d24-425d-a00f-2460a7a4a5ee.csv"
    with open(csv_path, "r") as f:
        reader = csv.DictReader(f)
        csv_rows = list(reader)
    missing = [r for r in csv_rows if r["url"] and r["url"] not in existing_urls]
    print(f"Found {len(missing)} missing CSV entries")
    for i, row in enumerate(missing, 1):
        try:
            tags = [t.strip() for t in row.get("tags", "").split(",") if t.strip()][:5]
            body = {
                "parent": {"database_id": DB_ID},
                "properties": {
                    "Name": {"title": [{"text": {"content": row["title"][:2000]}}]},
                    "Link": {"url": row["url"]},
                    "Tags": {"multi_select": [{"name": t} for t in tags]},
                },
            }
            resp = notion_req("POST", "https://api.notion.com/v1/pages", body)
            page_id = resp["id"]
            print(f"[Part3 {i}/{len(missing)}] Created \"{row['title'][:50]}\"")
            stats["p3_ok"] += 1
            # Try og:image
            og = get_og_image(row["url"])
            if og:
                set_cover(page_id, og)
                print(f"  → Set cover: {og[:80]}")
        except Exception as e:
            print(f"[Part3 {i}/{len(missing)}] Error \"{row['title'][:50]}\": {e}")
            stats["p3_skip"] += 1

    # Part 4: Tag dead orphans
    print("\n=== Part 4: Tag dead orphans ===")
    # Re-fetch to get updated state
    pages = fetch_all_pages()
    dead_re = re.compile(r'(screenshot|IMG_|IMG-|Screen Shot|Clipboard|image\s?\d|Untitled)', re.IGNORECASE)
    dead = [p for p in pages if not has_cover(p) and not get_link(p) and not BEHANCE_RE.match(get_title(p))]
    # Filter to likely dead filenames
    dead_tagged = [p for p in dead if dead_re.search(get_title(p)) or re.match(r'^[\w\-]+\.(jpg|jpeg|png|gif|webp)$', get_title(p), re.IGNORECASE)]
    print(f"Found {len(dead_tagged)} dead orphans to tag")
    for i, p in enumerate(dead_tagged, 1):
        try:
            title = get_title(p)
            tags = get_tags(p)
            add_tag(p["id"], tags, "dead-import")
            print(f"[Part4 {i}/{len(dead_tagged)}] Tagged \"{title}\"")
            stats["p4_ok"] += 1
        except Exception as e:
            print(f"[Part4 {i}/{len(dead_tagged)}] Error \"{get_title(p)}\": {e}")

    # Summary
    print("\n=== SUMMARY ===")
    print(f"Part 1 (Behance): {stats['p1_ok']} recovered, {stats['p1_skip']} skipped")
    print(f"Part 2 (OG image): {stats['p2_ok']} recovered, {stats['p2_skip']} skipped")
    print(f"Part 3 (CSV add): {stats['p3_ok']} created, {stats['p3_skip']} skipped")
    print(f"Part 4 (Dead tag): {stats['p4_ok']} tagged")
    print(f"Total recovered: {stats['p1_ok'] + stats['p2_ok'] + stats['p3_ok']}")

if __name__ == "__main__":
    main()
