#!/usr/bin/env python3
"""서울대보험쌤 × 영업지원 Google 광고 배너 생성 스크립트
파이프라인:
  1. Gemini API → 배경 이미지 생성
  2. HTML 템플릿 + Playwright → PNG 합성
"""

from __future__ import annotations

import base64
import json
import sys
import time
from pathlib import Path

import requests
from playwright.sync_api import sync_playwright

# ── 경로 설정 ──────────────────────────────────────────────────────────────
TOOL_DIR = Path("/home/jay/workspace/tools/ai-image-gen")
OUTPUT_DIR = Path("/home/jay/workspace/output/google-ads/banners")
BG_PATH = OUTPUT_DIR / "bg_snu_support.jpg"

TEMPLATE_1200 = OUTPUT_DIR / "overlay_snu_1200x628.html"
TEMPLATE_1080 = OUTPUT_DIR / "overlay_snu_1080x1080.html"

OUT_1200 = OUTPUT_DIR / "snu-support-1200x628.png"
OUT_1080 = OUTPUT_DIR / "snu-support-1080x1080.png"

# ── Gemini 배경 프롬프트 ───────────────────────────────────────────────────
BG_PROMPT = (
    "Bright warm cafe-style workspace, large window with green garden view outside. "
    "Morning light, golden hour atmosphere. "
    "One person sitting at a laptop, seen from the side, half face visible, gentle warm smile. "
    "Coffee cup and planner on the wooden table. "
    "Clean minimal interior, warm cream and gold tones. "
    "Feeling of a fresh new beginning, bright and welcoming. "
    "Photorealistic scene, high quality photography, natural lighting. "
    "No dark office, no technical equipment or server rooms, no diplomas or certificates. "
    "Soft bokeh background, warm color palette."
)

GEMINI_API_BASE = "https://generativelanguage.googleapis.com/v1beta"
GEMINI_SCOPE = "https://www.googleapis.com/auth/generative-language"


def get_auth_token() -> str:
    """gcloud_auth 모듈로 인증 토큰 획득"""
    sys.path.insert(0, str(TOOL_DIR))
    import gcloud_auth
    try:
        token = gcloud_auth.get_service_account_token(GEMINI_SCOPE)
        print(f"[인증] SA 토큰 획득 성공")
        return token
    except Exception as e:
        print(f"[인증] SA 토큰 실패: {e}, ADC 시도...")
        return gcloud_auth.get_access_token()


def generate_background(token: str, output_path: Path) -> Path:
    """Gemini API로 배경 이미지 생성"""
    models_to_try = [
        "gemini-2.0-flash-preview-image-generation",
        "gemini-2.0-flash-exp-image-generation",
        "gemini-3-pro-image-preview",
        "gemini-3.1-flash-image-preview",
        "imagen-3.0-generate-002",
    ]

    for model_id in models_to_try:
        print(f"[배경생성] 모델 시도: {model_id}")
        try:
            if model_id.startswith("imagen"):
                result = _call_imagen(token, model_id, output_path)
            else:
                result = _call_gemini_generate(token, model_id, output_path)
            if result:
                print(f"[배경생성] 성공: {output_path} ({output_path.stat().st_size:,} bytes)")
                return output_path
        except Exception as e:
            print(f"[배경생성] {model_id} 실패: {e}")
            continue

    raise RuntimeError("모든 Gemini 모델 호출 실패")


def _call_gemini_generate(token: str, model_id: str, output_path: Path) -> bool:
    """Gemini generateContent API 호출"""
    url = f"{GEMINI_API_BASE}/models/{model_id}:generateContent"
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }
    payload = {
        "contents": [{"parts": [{"text": BG_PROMPT}]}],
        "generationConfig": {"responseModalities": ["IMAGE", "TEXT"]},
    }
    resp = requests.post(url, headers=headers, json=payload, timeout=180)
    if resp.status_code in (403, 404):
        raise RuntimeError(f"HTTP {resp.status_code}: {resp.text[:200]}")
    resp.raise_for_status()

    data = resp.json()
    candidates = data.get("candidates", [])
    if not candidates:
        raise RuntimeError(f"응답에 candidates 없음: {json.dumps(data)[:300]}")

    parts = candidates[0].get("content", {}).get("parts", [])
    for part in parts:
        if "inlineData" in part:
            mime = part["inlineData"].get("mimeType", "image/jpeg")
            img_bytes = base64.b64decode(part["inlineData"]["data"])
            # jpg로 저장
            save_path = output_path.with_suffix(".jpg")
            save_path.write_bytes(img_bytes)
            # 경로 업데이트 (외부에서 참조하므로 이름 변경)
            if save_path != output_path:
                output_path.parent.mkdir(parents=True, exist_ok=True)
                import shutil
                shutil.copy(str(save_path), str(output_path))
            return True
    raise RuntimeError("이미지 데이터 없음 (inlineData 없음)")


def _call_imagen(token: str, model_id: str, output_path: Path) -> bool:
    """Imagen API 호출"""
    url = f"{GEMINI_API_BASE}/models/{model_id}:predict"
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }
    payload = {
        "instances": [{"prompt": BG_PROMPT}],
        "parameters": {
            "sampleCount": 1,
            "aspectRatio": "1:1",
        },
    }
    resp = requests.post(url, headers=headers, json=payload, timeout=180)
    if resp.status_code in (403, 404):
        raise RuntimeError(f"HTTP {resp.status_code}")
    resp.raise_for_status()

    data = resp.json()
    predictions = data.get("predictions", [])
    if not predictions:
        raise RuntimeError("predictions 없음")

    img_b64 = predictions[0].get("bytesBase64Encoded", "")
    if not img_b64:
        raise RuntimeError("이미지 데이터 없음")

    img_bytes = base64.b64decode(img_b64)
    output_path.write_bytes(img_bytes)
    return True


def capture_banner(
    template_path: Path,
    bg_path: Path,
    output_path: Path,
    width: int,
    height: int,
) -> None:
    """Playwright로 HTML 템플릿을 PNG로 캡처"""
    if not template_path.exists():
        raise FileNotFoundError(f"템플릿 없음: {template_path}")
    if not bg_path.exists():
        raise FileNotFoundError(f"배경 이미지 없음: {bg_path}")

    template_url = f"file://{template_path.resolve()}"
    bg_file_url = f"file://{bg_path.resolve()}"

    with sync_playwright() as p:
        browser = p.chromium.launch()
        try:
            page = browser.new_page(viewport={"width": width, "height": height})
            page.goto(template_url, wait_until="networkidle")
            page.evaluate(f"""() => {{
                window.BG_IMAGE_PATH = "{bg_file_url}";
                window.SCENARIO_DATA = {{}};
                if (typeof render === 'function') {{
                    render(window.SCENARIO_DATA, window.BG_IMAGE_PATH);
                }}
            }}""")
            # 폰트·렌더링 완료 대기
            page.wait_for_timeout(2000)
            output_path.parent.mkdir(parents=True, exist_ok=True)
            page.screenshot(path=str(output_path), type="png")
            print(f"[캡처] {output_path} ({output_path.stat().st_size:,} bytes)")
        finally:
            browser.close()


def main() -> None:
    print("=" * 60)
    print("서울대보험쌤 × 영업지원 Google 광고 배너 생성")
    print("=" * 60)
    total_start = time.time()

    # 1. 인증 토큰
    print("\n[1/3] 인증 토큰 획득 중...")
    token = get_auth_token()

    # 2. Gemini 배경 이미지 생성
    print("\n[2/3] Gemini 배경 이미지 생성 중...")
    bg_path = generate_background(token, BG_PATH)

    # 3. HTML + Playwright 합성
    print("\n[3/3] HTML 오버레이 합성 중...")

    # 1200x628
    print("  → 1200x628 배너 캡처...")
    capture_banner(TEMPLATE_1200, bg_path, OUT_1200, 1200, 628)

    # 1080x1080
    print("  → 1080x1080 배너 캡처...")
    capture_banner(TEMPLATE_1080, bg_path, OUT_1080, 1080, 1080)

    elapsed = time.time() - total_start
    print("\n" + "=" * 60)
    print(f"완료! 총 소요: {elapsed:.1f}초")
    print(f"  [1] {OUT_1200}")
    print(f"  [2] {OUT_1080}")
    print("=" * 60)


if __name__ == "__main__":
    main()
