#!/usr/bin/env python3
"""Final attempt: search DDG text, scrape recipe pages for actual images."""

import csv
import json
import re
import sys
import time
from pathlib import Path

import requests
from bs4 import BeautifulSoup
from ddgs import DDGS

WORKDIR = Path("/home/jbrechtel/recipes/.worktrees/recipe-images")
HEADERS = {
    "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
}
SKIP_DOMAINS = {"pinterest", "facebook", "instagram", "twitter", "youtube", "tiktok"}
MIN_IMAGE_SIZE = 10000  # 10KB minimum for a recipe photo


def search_url(query: str) -> str | None:
    """Search and return first relevant recipe page URL."""
    try:
        results = list(DDGS().text(query, max_results=8))
    except Exception as e:
        print(f"  Search error: {e}", file=sys.stderr)
        return None

    for r in results:
        url = r.get("href", "")
        domain = url.split("/")[2] if "//" in url else ""
        if any(s in domain for s in SKIP_DOMAINS):
            continue
        # Prefer recipe sites
        if any(kw in domain for kw in ["recipe", "cook", "food", "kitchen", "nytimes", "loveandlemons"]):
            return url

    # Return first non-wikipedia result
    for r in results:
        url = r.get("href", "")
        if "wikipedia.org" not in url:
            return url
    return None


def find_recipe_images(url: str) -> list[str]:
    """Fetch a page and find actual recipe/food images."""
    try:
        resp = requests.get(url, headers=HEADERS, timeout=15, allow_redirects=True)
        resp.raise_for_status()
    except requests.RequestException:
        return []

    soup = BeautifulSoup(resp.text, "html.parser")
    images = []

    # 1. Check JSON-LD for recipe image
    for script in soup.find_all("script", type="application/ld+json"):
        try:
            data = json.loads(script.string)
        except (json.JSONDecodeError, TypeError):
            continue
        # Handle list or single
        items = data if isinstance(data, list) else [data]
        for item in items:
            if not isinstance(item, dict):
                continue
            if item.get("@type") == "Recipe":
                img = item.get("image")
                if isinstance(img, str):
                    images.append(img)
                elif isinstance(img, list):
                    for i in img:
                        if isinstance(i, str):
                            images.append(i)
                        elif isinstance(i, dict):
                            u = i.get("contentUrl") or i.get("url", "")
                            if u:
                                images.append(u)
                elif isinstance(img, dict):
                    u = img.get("contentUrl") or img.get("url", "")
                    if u:
                        images.append(u)

    # 2. Check og:image
    for meta in soup.find_all("meta"):
        content = meta.get("content", "")
        if (meta.get("property") == "og:image" or meta.get("name") == "og:image" or meta.get("name") == "twitter:image"):
            if content and "logo" not in content.lower():
                images.append(content)

    # 3. Check all img tags for large, relevant images
    for img in soup.find_all("img"):
        src = img.get("src") or img.get("data-src") or ""
        if not src.startswith("http"):
            continue
        src_lower = src.lower()
        if any(kw in src_lower for kw in ["logo", "avatar", "icon", "banner", "pixel", "spacer", "thumb"]):
            continue
        # Check for recipe-related class/id
        parent_classes = ""
        parent = img.parent
        if parent:
            parent_classes = " ".join(parent.get("class", []) or []) + " " + (parent.get("id") or "")
        if any(kw in parent_classes.lower() for kw in ["logo", "nav", "header", "footer", "menu", "icon"]):
            continue
        images.append(src)

    # Deduplicate
    seen = set()
    unique = []
    for img in images:
        if img not in seen:
            seen.add(img)
            unique.append(img)

    return unique


def download_image(url: str, dest: Path) -> bool:
    """Download image, validate it's a real image."""
    try:
        resp = requests.get(url, headers=HEADERS, timeout=30, stream=True)
        resp.raise_for_status()
        ct = resp.headers.get("content-type", "")
        if not ct.startswith("image/"):
            return False
        content = resp.content
        if len(content) < MIN_IMAGE_SIZE:
            return False
        dest.write_bytes(content)
        return True
    except requests.RequestException:
        return False


def get_title(filepath: Path) -> str:
    content = filepath.read_text(encoding="utf-8")
    m = re.search(r"^title:\s*(.+)$", content, re.MULTILINE)
    if m:
        return m.group(1).strip()
    return filepath.stem.replace("_", " ").replace("-", " ")


def add_image_field(filepath: Path, slug: str):
    url = f"https://roux.roo.lol/recipe-images/{slug}.webp"
    content = filepath.read_text(encoding="utf-8")
    if re.search(r"^image:", content, re.MULTILINE):
        content = re.sub(r"^image:.*$", f"image: {url}", count=1, flags=re.MULTILINE, string=content)
    else:
        content = re.sub(r"^---$", f"image: {url}\n---", count=1, flags=re.MULTILINE, string=content)
    filepath.write_text(content, encoding="utf-8")
    print(f"  Updated {filepath.name}", file=sys.stderr)


def get_source_url(filepath: Path) -> str | None:
    content = filepath.read_text(encoding="utf-8")
    m = re.search(r"^source:\s*(.+)$", content, re.MULTILINE)
    if m:
        val = m.group(1).strip()
        if val.startswith("http"):
            return val
    return None


def main():
    csv_file = WORKDIR / "docs" / "no-image-has-fm.csv"

    recipes = []
    with open(csv_file) as f:
        reader = csv.reader(f, delimiter="|")
        for row in reader:
            if len(row) >= 2:
                recipes.append((row[0].strip(), row[1].strip()))

    success = []
    failed = []

    for filename, slug in recipes:
        filepath = WORKDIR / filename
        if not filepath.exists():
            failed.append(slug)
            continue

        dest = WORKDIR / "recipe-images" / f"{slug}.webp"

        # Skip if already has image AND file exists
        content = filepath.read_text(encoding="utf-8")
        has_field = bool(re.search(r"^image:", content, re.MULTILINE))
        has_file = dest.exists()
        if has_field and has_file and dest.stat().st_size > 10000:
            print(f"[{slug}] Already done, skipping", file=sys.stderr)
            success.append(slug)
            continue

        title = get_title(filepath)
        query = f"{title} recipe"

        print(f"[{slug}] Searching: {query}", file=sys.stderr)
        page_url = search_url(query)
        if not page_url:
            print(f"  No search results", file=sys.stderr)
            failed.append(slug)
            continue

        print(f"  Page: {page_url}", file=sys.stderr)
        time.sleep(0.3)

        img_urls = find_recipe_images(page_url)
        if not img_urls:
            print(f"  No images found on page", file=sys.stderr)
            failed.append(slug)
            continue

        downloaded = False
        for img_url in img_urls[:5]:
            print(f"  Trying: {img_url[:80]}...", file=sys.stderr)
            if download_image(img_url, dest):
                print(f"  Downloaded ({dest.stat().st_size} bytes)", file=sys.stderr)
                add_image_field(filepath, slug)
                downloaded = True
                break
            time.sleep(0.2)

        if downloaded:
            success.append(slug)
        else:
            failed.append(slug)

        time.sleep(0.5)

    print(f"\n=== Results ===", file=sys.stderr)
    print(f"Success: {len(success)}", file=sys.stderr)
    print(f"Failed: {len(failed)}", file=sys.stderr)
    if failed:
        print(f"Failed: {', '.join(failed)}", file=sys.stderr)


if __name__ == "__main__":
    main()
