"""
Stage 2 — Creative analyzer.

Input:  folder of PNG screenshots of Google Ads Transparency Center pages.
Output:
  - creatives.json — list of all identified creatives with full analysis
  - crops/{brand}-creative-{NN}.png — individual cropped creative images
  - report.md — auto-generated markdown report

Usage:
  python3 analyze_creatives.py --input-dir /tmp/cu-poc/perla --brand "Perla Helsa" \\
      --region "Україна" --output-dir /srv/reports/assets/perla-helsa-2026-04-22
"""
from __future__ import annotations

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

from PIL import Image
from google import genai
from google.genai import types

KEY_PATH = Path("/srv/passepartout/google/gemini-computer-use-research.key")
MODEL_ANALYZER = "gemini-2.5-pro"  # Pro for better reasoning/reviews

VISION_PROMPT = """Ти — медіа-аналітик рекламних креативів. На скріншоті Google Ads Transparency Center є картки оголошень.
Для КОЖНОГО окремого креативу поверни структурований запис.

**Ігноруй:**
- Обрізані картки (видно лише частина — не помістились у скрін)
- Дублі одного і того ж оголошення
- "На жаль, зараз не можемо показати це оголошення" (порожні slot)
- Empty placeholders

**Включай:**
- Search text ads (текст + URL)
- Image banners (графічні banner-ads)
- Blog-style banners (content-as-ad)
- Відео-плейсмент превʼю (якщо видно)

Формат ВИХОДУ — строгий JSON:
{
  "creatives": [
    {
      "id": "01",
      "bbox_norm": [y_min, x_min, y_max, x_max],   // 0-1000 нормалізовано (y_min, x_min, y_max, x_max)
      "format": "search_text" | "image_banner" | "blog_banner" | "video_placement",
      "topic": "collagen" | "magnesium" | "melatonin" | "iron" | "creatine" | "vitamin_d3" | "biotin" | "immunity" | "omega" | "general" | "other",
      "headline": "заголовок точно як у креативі",
      "body_text": "опис точно як у креативі (перші 2-3 речення)",
      "url_shown": "відображений URL якщо видно (напр. www.brand.ua/продукт)",
      "visual_description": "1-2 речення про візуал: кольори, об'єкти, персонажі, стиль",
      "angle": "beauty | pain_trigger | premium | innovation | portfolio | educational | promo | transactional",
      "hook": "що саме чіпляє увагу — 1 речення",
      "cta": "дослівне CTA з креативу або «відсутнє»",
      "promo": "вказана знижка/акція чи null",
      "funnel_position": "TOFU | MOFU | BOFU | retargeting",
      "marketing_review": "2-3 речення маркетингового аналізу: чому саме так, що це відкриває/закриває в funnel'і, чи є сильний/слабкий хід"
    }
  ]
}

Поверни ТІЛЬКИ JSON, без markdown-огортки і без пояснень."""


def load_key() -> str:
    return KEY_PATH.read_text().strip()


def norm_to_px(y_min: int, x_min: int, y_max: int, x_max: int, W: int, H: int, pad: int = 8) -> tuple[int, int, int, int]:
    return (
        max(0, int(x_min * W / 1000) - pad),
        max(0, int(y_min * H / 1000) - pad),
        min(W, int(x_max * W / 1000) + pad),
        min(H, int(y_max * H / 1000) + pad),
    )


def slugify(text: str) -> str:
    text = re.sub(r"[^a-zA-Zа-яА-ЯїЇєЄіІґҐ0-9]+", "-", text.lower())
    return text.strip("-")[:50]


def dedup(creatives: list[dict]) -> list[dict]:
    """Remove duplicates by headline similarity."""
    seen = set()
    result = []
    for c in creatives:
        key = (c.get("headline", "")[:50].lower(), c.get("format"))
        if key in seen:
            continue
        seen.add(key)
        result.append(c)
    return result


def analyze(input_dir: Path, brand: str, region: str, output_dir: Path) -> dict:
    client = genai.Client(api_key=load_key())
    output_dir.mkdir(parents=True, exist_ok=True)
    crops_dir = output_dir / "crops"
    crops_dir.mkdir(exist_ok=True)

    # Collect all creatives with their source info
    all_creatives: list[dict] = []
    screenshots = sorted(input_dir.glob("step-*.png"))
    print(f"📥 Found {len(screenshots)} screenshots in {input_dir}")

    total_in, total_out = 0, 0
    for shot in screenshots:
        img = Image.open(shot)
        print(f"\n🔍 Analyzing {shot.name}  {img.size}")
        try:
            resp = client.models.generate_content(
                model=MODEL_ANALYZER,
                contents=[
                    VISION_PROMPT,
                    types.Part.from_bytes(data=shot.read_bytes(), mime_type="image/png"),
                ],
                config=types.GenerateContentConfig(
                    response_mime_type="application/json",
                    temperature=0.3,
                ),
            )
        except Exception as e:
            print(f"  ⚠️ API err: {e}")
            continue
        um = getattr(resp, "usage_metadata", None)
        if um:
            t_in = getattr(um, "prompt_token_count", 0) or 0
            t_out = getattr(um, "candidates_token_count", 0) or 0
            total_in += t_in; total_out += t_out
            print(f"  tokens: in={t_in:,} out={t_out:,}")
        try:
            data = json.loads(resp.text)
        except Exception as e:
            print(f"  ⚠️ parse err: {e}")
            continue
        n = len(data.get("creatives", []))
        print(f"  → {n} creatives found")
        for c in data.get("creatives", []):
            c["_source_screenshot"] = shot.name
            c["_img_size"] = img.size
            all_creatives.append(c)

    # Cost summary (Gemini 2.5 Pro pricing as of 2026-04)
    cost_in = total_in * 1.25 / 1_000_000
    cost_out = total_out * 10.0 / 1_000_000
    print(f"\n💰 Stage 2 cost: ${cost_in + cost_out:.4f}  (in {total_in:,} → ${cost_in:.4f} + out {total_out:,} → ${cost_out:.4f})")

    # Dedup by headline+format
    creatives = dedup(all_creatives)
    print(f"\n✅ Unique creatives after dedup: {len(creatives)}")

    # Crop each
    for i, c in enumerate(creatives, 1):
        c["id"] = f"{i:02d}"
        try:
            y0, x0, y1, x1 = c["bbox_norm"]
            W, H = c["_img_size"]
            box = norm_to_px(y0, x0, y1, x1, W, H)
            src = input_dir / c["_source_screenshot"]
            slug = slugify(c.get("headline", f"creative-{i}"))[:40]
            fname = f"creative-{i:02d}-{c.get('topic','other')}-{slug}.png"
            Image.open(src).crop(box).save(crops_dir / fname, optimize=True)
            c["_crop_file"] = fname
            print(f"  ✓ {fname}")
        except Exception as e:
            print(f"  ⚠️ crop err for #{i}: {e}")
            c["_crop_file"] = None

    # Save raw JSON
    payload = {
        "brand": brand,
        "region": region,
        "generated_at": time.strftime("%Y-%m-%d %H:%M:%S"),
        "model": MODEL_ANALYZER,
        "creatives_total": len(creatives),
        "creatives": creatives,
    }
    (output_dir / "creatives.json").write_text(json.dumps(payload, ensure_ascii=False, indent=2))
    print(f"\n💾 Saved creatives.json ({len(creatives)} entries)")
    return payload


def write_report(data: dict, output_dir: Path, report_path: Path) -> None:
    brand = data["brand"]
    region = data["region"]
    creatives = data["creatives"]
    by_topic: dict[str, list] = {}
    for c in creatives:
        by_topic.setdefault(c.get("topic", "other"), []).append(c)

    lines = [
        f"# {brand} — Google Ads creative review ({region})",
        "",
        f"> Дата: {data['generated_at'][:10]}",
        f"> Джерело: Google Ads Transparency Center, регіон {region}, останні 30 днів",
        f"> Метод: 2-stage AI pipeline — Collector (Computer Use browser agent) + Analyzer ({data['model']} Vision, structured JSON)",
        f"> Виявлено креативів: **{len(creatives)}**",
        "",
        "## 📊 Розподіл по темах",
        "",
        "| Тема | Креативів |",
        "|---|---|",
    ]
    for topic, items in sorted(by_topic.items(), key=lambda kv: -len(kv[1])):
        lines.append(f"| {topic} | {len(items)} |")
    lines += ["", "---", "", "## 🎨 Усі креативи з аналізом", ""]

    for c in creatives:
        crop = c.get("_crop_file")
        lines.append(f"### #{c['id']} — {c.get('headline', '(без заголовка)')}")
        lines.append("")
        if crop:
            rel_url = f"/reports/assets/{output_dir.name}/crops/{crop}"
            lines.append(f"![creative]({rel_url})")
            lines.append("")
        lines.append(f"**Формат:** `{c.get('format','?')}` · **Тема:** `{c.get('topic','?')}` · **Funnel:** `{c.get('funnel_position','?')}` · **Angle:** `{c.get('angle','?')}`")
        lines.append("")
        if c.get("url_shown"):
            lines.append(f"**URL:** `{c['url_shown']}`")
            lines.append("")
        if c.get("body_text"):
            lines.append(f"**Текст:** *{c['body_text']}*")
            lines.append("")
        if c.get("visual_description"):
            lines.append(f"**Візуал:** {c['visual_description']}")
            lines.append("")
        hook_line = f"**🎯 Hook:** {c.get('hook','—')}"
        cta_line = f"**CTA:** {c.get('cta','—')}"
        promo = c.get("promo")
        if promo:
            cta_line += f" · **Promo:** {promo}"
        lines.append(hook_line + " · " + cta_line)
        lines.append("")
        if c.get("marketing_review"):
            lines.append(f"> {c['marketing_review']}")
            lines.append("")
        lines.append("---")
        lines.append("")

    # Angles summary
    angle_map: dict[str, list] = {}
    for c in creatives:
        angle_map.setdefault(c.get("angle", "other"), []).append(c["id"])
    lines.append("## 🎯 Meta-аналіз angles")
    lines.append("")
    lines.append("| Angle | Креативи |")
    lines.append("|---|---|")
    for a, ids in sorted(angle_map.items(), key=lambda kv: -len(kv[1])):
        lines.append(f"| {a} | {', '.join('#' + i for i in ids)} |")
    lines.append("")

    # Funnel summary
    funnel_map: dict[str, list] = {}
    for c in creatives:
        funnel_map.setdefault(c.get("funnel_position", "?"), []).append(c["id"])
    lines.append("## 🔄 Розподіл по funnel-позиції")
    lines.append("")
    lines.append("| Funnel | Креативи |")
    lines.append("|---|---|")
    for f, ids in sorted(funnel_map.items(), key=lambda kv: -len(kv[1])):
        lines.append(f"| {f} | {', '.join('#' + i for i in ids)} |")
    lines.append("")

    lines.append("## 🛠 Pipeline")
    lines.append("")
    lines.append(f"- **Stage 1 (Collector):** Gemini 2.5 Computer Use browser agent. Сканує Transparency Center, збирає сирі скріни екранів з креативами.")
    lines.append(f"- **Stage 2 (Analyzer):** {data['model']} Vision з structured JSON-mode. Для кожного скрину — масив креативів з bbox, headline, body, visual, angle, hook, CTA, funnel, review.")
    lines.append(f"- **Crop:** PIL за отриманими bbox — автоматичні вирізки, однорідний формат.")
    lines.append(f"- **Report:** шаблон «image → factsheet → review» для кожного креативу.")
    lines.append("")

    report_path.write_text("\n".join(lines))
    print(f"📝 Report written: {report_path}")


def main() -> None:
    ap = argparse.ArgumentParser()
    ap.add_argument("--input-dir", type=Path, required=True)
    ap.add_argument("--brand", required=True)
    ap.add_argument("--region", default="Україна")
    ap.add_argument("--output-dir", type=Path, required=True, help="/srv/reports/assets/<slug>")
    ap.add_argument("--report-path", type=Path, required=True, help="/srv/reports/<filename>.md")
    args = ap.parse_args()

    data = analyze(args.input_dir, args.brand, args.region, args.output_dir)
    write_report(data, args.output_dir, args.report_path)


if __name__ == "__main__":
    main()
