#!/usr/bin/env python3
"""
Image Analyzer for Notion Inspiration DB
- Pulls images from Mac Studio
- Analyzes with vision to generate tags
- Uploads to image host for cover URL
- Updates Notion with cover and tags
"""

import argparse
import base64
import json
import os
import subprocess
import sys
import tempfile
import time
from pathlib import Path

import requests

# Configuration
NOTION_API_KEY_PATH = "/home/clawd/secrets/notion/api_key"
NOTION_DB_ID = "2ff330c2-8646-81f0-bbd9-ec474393d7a5"
MAC_NODE = "Mac Studio"
DESKTOP_INSPO = "/Users/assafdagan/Desktop/inspo"
DATA_FILE = "/home/clawd/workspace/data/local_images.json"
NOTION_DELAY = 0.3

# Gemini for vision
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "AIzaSyDXqYZInk83iVV4mD29pSuHQKbgkiI1x9Q")


def load_notion_key():
    with open(NOTION_API_KEY_PATH) as f:
        return f.read().strip()


def load_images():
    with open(DATA_FILE) as f:
        return json.load(f)


def get_image_path(title, source):
    """Reconstruct the file path on Mac Studio."""
    # Source is like "Desktop/inspo/MJ Articles"
    # We need to map it back to actual path
    subfolder = source.replace("Desktop/inspo", "").lstrip("/")
    if subfolder:
        return f"{DESKTOP_INSPO}/{subfolder}/{title}"
    return f"{DESKTOP_INSPO}/{title}"


def pull_image_from_mac(filepath, local_path):
    """Pull image from Mac Studio using nodes.run or scp."""
    # Use base64 encoding to transfer via stdout
    # macOS base64 requires -i flag for input file
    cmd = f'base64 -i "{filepath}"'
    
    # We'll use subprocess to call openclaw nodes run
    result = subprocess.run(
        ["openclaw", "nodes", "run", "--node", MAC_NODE, "--", "bash", "-c", cmd],
        capture_output=True,
        text=True,
        timeout=60,
    )
    
    if result.returncode != 0:
        return False, result.stderr
    
    # Decode base64 and save
    try:
        img_data = base64.b64decode(result.stdout.strip())
        with open(local_path, "wb") as f:
            f.write(img_data)
        return True, local_path
    except Exception as e:
        return False, str(e)


def analyze_image_with_vision(image_path):
    """Use Gemini vision to analyze image and generate tags."""
    with open(image_path, "rb") as f:
        img_data = base64.b64encode(f.read()).decode()
    
    # Determine mime type
    ext = Path(image_path).suffix.lower()
    mime_map = {
        ".jpg": "image/jpeg",
        ".jpeg": "image/jpeg",
        ".png": "image/png",
        ".gif": "image/gif",
        ".webp": "image/webp",
    }
    mime_type = mime_map.get(ext, "image/jpeg")
    
    url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={GEMINI_API_KEY}"
    
    payload = {
        "contents": [{
            "parts": [
                {
                    "inlineData": {
                        "mimeType": mime_type,
                        "data": img_data,
                    }
                },
                {
                    "text": """Analyze this image for a design inspiration library.

Return a JSON object with:
1. "title": A short descriptive title (max 60 chars)
2. "description": One sentence describing what this is
3. "tags": Array of 3-8 relevant tags from this list (pick most relevant):
   - Style: Minimalist, Bold, Playful, Elegant, Retro, Modern, Organic, Geometric
   - Type: Branding, Packaging, Typography, Illustration, Photography, UI/UX, 3D, Motion, Logo, Poster, Editorial
   - Subject: Food, Fashion, Architecture, Product, Portrait, Landscape, Abstract, Pattern
   - Color: Colorful, Monochrome, Pastel, Vibrant, Muted, Earth Tones
   - Industry: Tech, Food & Drink, Beauty, Lifestyle, Corporate, Entertainment, Art

Return ONLY valid JSON, no markdown."""
                }
            ]
        }],
        "generationConfig": {
            "temperature": 0.3,
            "maxOutputTokens": 500,
        }
    }
    
    try:
        resp = requests.post(url, json=payload, timeout=30)
        resp.raise_for_status()
        data = resp.json()
        
        text = data["candidates"][0]["content"]["parts"][0]["text"]
        # Clean up potential markdown
        text = text.strip()
        if text.startswith("```"):
            text = text.split("\n", 1)[1]
            if text.endswith("```"):
                text = text[:-3]
        
        return json.loads(text)
    except Exception as e:
        return {"error": str(e)}


def upload_to_imgbb(image_path):
    """Upload image to imgbb for free hosting."""
    # imgbb free tier - no API key needed for basic upload
    # Actually imgbb needs API key, let's use a different approach
    # We'll use file.io or similar
    
    # Alternative: use catbox.moe which is free
    with open(image_path, "rb") as f:
        files = {"fileToUpload": f}
        data = {"reqtype": "fileupload"}
        
        try:
            resp = requests.post(
                "https://catbox.moe/user/api.php",
                files=files,
                data=data,
                timeout=60,
            )
            if resp.status_code == 200 and resp.text.startswith("https://"):
                return resp.text.strip()
        except Exception:
            pass
    
    return None


def update_notion_page(api_key, page_id, title=None, tags=None, cover_url=None):
    """Update Notion page with new info."""
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Notion-Version": "2022-06-28",
        "Content-Type": "application/json",
    }
    
    url = f"https://api.notion.com/v1/pages/{page_id}"
    
    payload = {}
    
    # Update properties
    props = {}
    
    if title:
        props["Name"] = {
            "title": [{"text": {"content": title[:2000]}}]
        }
    
    if tags:
        props["Tags"] = {
            "multi_select": [{"name": tag} for tag in tags[:10]]
        }
    
    if props:
        payload["properties"] = props
    
    # Update cover
    if cover_url:
        payload["cover"] = {
            "type": "external",
            "external": {"url": cover_url}
        }
    
    if not payload:
        return True
    
    try:
        resp = requests.patch(url, headers=headers, json=payload, timeout=30)
        return resp.status_code == 200
    except Exception:
        return False


def process_image(api_key, item, temp_dir):
    """Process a single image: pull, analyze, upload, update."""
    title = item["title"]
    source = item["source"]
    page_id = item["id"]
    
    print(f"\nProcessing: {title[:40]}...")
    
    # 1. Get file path
    filepath = get_image_path(title, source)
    local_path = os.path.join(temp_dir, title)
    
    # 2. Pull from Mac
    print("  Pulling from Mac Studio...", end=" ")
    success, result = pull_image_from_mac(filepath, local_path)
    if not success:
        print(f"✗ ({result[:50]})")
        return False
    print("✓")
    
    # 3. Analyze with vision
    print("  Analyzing with vision...", end=" ")
    analysis = analyze_image_with_vision(local_path)
    if "error" in analysis:
        print(f"✗ ({analysis['error'][:50]})")
        # Still try to upload for cover
        new_title = None
        tags = None
    else:
        print("✓")
        new_title = analysis.get("title")
        tags = analysis.get("tags", [])
        print(f"    Title: {new_title}")
        print(f"    Tags: {', '.join(tags[:5])}")
    
    # 4. Upload for cover
    print("  Uploading for cover...", end=" ")
    cover_url = upload_to_imgbb(local_path)
    if cover_url:
        print(f"✓")
    else:
        print("✗")
    
    # 5. Update Notion
    print("  Updating Notion...", end=" ")
    success = update_notion_page(api_key, page_id, new_title, tags, cover_url)
    if success:
        print("✓")
    else:
        print("✗")
    
    # Cleanup
    try:
        os.remove(local_path)
    except:
        pass
    
    return success


def main():
    parser = argparse.ArgumentParser(description="Analyze and update image items")
    parser.add_argument("--limit", type=int, default=10, help="Number of images to process")
    parser.add_argument("--offset", type=int, default=0, help="Start from this index")
    
    args = parser.parse_args()
    
    # Load images
    images = load_images()
    print(f"Total images: {len(images)}")
    
    # Filter to ones needing processing (no cover)
    needs_work = [i for i in images if not i.get("has_cover")]
    print(f"Need processing: {len(needs_work)}")
    
    # Select batch
    batch = needs_work[args.offset:args.offset + args.limit]
    print(f"Processing batch: {args.offset} to {args.offset + len(batch)}")
    
    api_key = load_notion_key()
    
    success = 0
    failed = 0
    
    with tempfile.TemporaryDirectory() as temp_dir:
        for item in batch:
            if process_image(api_key, item, temp_dir):
                success += 1
            else:
                failed += 1
            time.sleep(NOTION_DELAY)
    
    print(f"\n=== RESULTS ===")
    print(f"Success: {success}")
    print(f"Failed: {failed}")
    print(f"Remaining: {len(needs_work) - args.offset - len(batch)}")


if __name__ == "__main__":
    main()
