#!/usr/bin/env python3
"""Concept #08 Emotional Narrative - 하이브리드 이미지 생성 스크립트.

파이프라인:
1. Gemini API로 따뜻한 파스텔 배경 사진 생성 → bg.jpg
2. HTML 템플릿에 배경 이미지 삽입
3. Playwright로 1080x1080 PNG 캡처 → sample.png
"""

from __future__ import annotations

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

# gcloud_auth 모듈 경로 추가
sys.path.insert(0, "/home/jay/workspace/tools/ai-image-gen")

import gcloud_auth
import requests
from playwright.sync_api import sync_playwright

OUTPUT_DIR = Path("/home/jay/workspace/output/meta-ads/concept-catalog/08-emotional-narrative")
BG_PATH = OUTPUT_DIR / "bg.jpg"
TEMPLATE_PATH = OUTPUT_DIR / "template.html"
SAMPLE_PATH = OUTPUT_DIR / "sample.png"

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

BG_PROMPT = (
    "Warm pastel lifestyle photo, soft afternoon sunlight streaming through a window, "
    "a clean wooden desk with a cup of coffee and an open notebook, cream and amber tones, "
    "shallow depth of field, calm and hopeful mood, no people, no text, "
    "suitable for financial service advertisement background, "
    "1080x1080px square format, photorealistic"
)

MODELS = [
    "gemini-2.0-flash-preview-image-generation",
    "gemini-3-pro-image-preview",
    "gemini-3.1-flash-image-preview",
    "imagen-3.0-generate-001",
]


def generate_bg_image(token: str) -> bool:
    """Gemini API로 배경 이미지를 생성하고 BG_PATH에 저장합니다."""
    print("[배경 생성] Gemini API 호출 중...")

    for model_id in MODELS:
        print(f"  모델 시도: {model_id}")
        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"]},
        }

        try:
            resp = requests.post(url, headers=headers, json=payload, timeout=120)
            if resp.status_code in (400, 403, 404):
                print(f"  HTTP {resp.status_code} - 다음 모델로 시도")
                continue

            resp.raise_for_status()
            data = resp.json()
            candidates = data.get("candidates", [])
            if not candidates:
                print("  candidates 없음 - 다음 모델로 시도")
                continue

            parts = candidates[0].get("content", {}).get("parts", [])
            image_part = next((p for p in parts if "inlineData" in p), None)
            if image_part is None:
                text_parts = [p.get("text", "") for p in parts if "text" in p]
                print(f"  이미지 파트 없음. 텍스트: {text_parts[:1]} - 다음 모델로 시도")
                continue

            mime_type = image_part["inlineData"].get("mimeType", "image/jpeg")
            image_bytes = base64.b64decode(image_part["inlineData"]["data"])

            # 확장자 결정
            if "png" in mime_type:
                save_path = BG_PATH.with_suffix(".png")
            else:
                save_path = BG_PATH  # .jpg

            save_path.write_bytes(image_bytes)
            # BG_PATH가 다른 확장자면 심링크 대신 rename
            if save_path != BG_PATH:
                save_path.rename(BG_PATH)

            print(f"  [OK] 배경 저장: {BG_PATH} ({len(image_bytes):,} bytes, {mime_type})")
            return True

        except requests.HTTPError as e:
            print(f"  HTTP 오류: {e.response.status_code} - 다음 모델로 시도")
            continue
        except Exception as e:
            print(f"  오류: {e} - 다음 모델로 시도")
            continue

    return False


def render_html_to_png(bg_path: Path) -> None:
    """Playwright로 HTML 템플릿을 1080x1080 PNG로 캡처합니다."""
    print("[HTML 렌더링] Playwright 캡처 시작...")

    # 템플릿에 배경 이미지 경로 삽입
    template_content = TEMPLATE_PATH.read_text(encoding="utf-8")
    bg_url = f"file://{bg_path.resolve()}"
    rendered_content = template_content.replace("BG_IMAGE_URL", bg_url)

    # 임시 HTML 파일 저장
    temp_html = OUTPUT_DIR / "template_rendered.html"
    temp_html.write_text(rendered_content, encoding="utf-8")

    with sync_playwright() as p:
        browser = p.chromium.launch()
        try:
            page = browser.new_page(viewport={"width": 1080, "height": 1080})
            page.goto(f"file://{temp_html.resolve()}", wait_until="networkidle")
            # 폰트 로딩 대기
            page.wait_for_timeout(2000)
            page.screenshot(path=str(SAMPLE_PATH), type="png", clip={"x": 0, "y": 0, "width": 1080, "height": 1080})
            print(f"  [OK] PNG 저장: {SAMPLE_PATH}")
        finally:
            browser.close()


def verify_output() -> None:
    """출력 이미지 해상도 확인."""
    try:
        from PIL import Image
        with Image.open(SAMPLE_PATH) as img:
            w, h = img.size
            print(f"[검증] 해상도: {w}x{h}px ({'OK' if w == 1080 and h == 1080 else 'MISMATCH'})")
    except ImportError:
        size_kb = SAMPLE_PATH.stat().st_size / 1024
        print(f"[검증] 파일 크기: {size_kb:.0f} KB (PIL 없어서 해상도 미확인)")


def main() -> None:
    print("=" * 60)
    print("Concept #08 Emotional Narrative - 하이브리드 이미지 생성")
    print("=" * 60)

    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

    # 1. 인증 토큰 획득
    print("\n[인증] SA 토큰 획득 중...")
    try:
        token = gcloud_auth.get_service_account_token(GEMINI_SCOPE)
        print(f"  토큰 획득 성공 (길이: {len(token)} chars)")
    except Exception as e:
        print(f"  SA 토큰 실패: {e}")
        print("  gcloud CLI fallback 시도...")
        try:
            token = gcloud_auth.get_access_token()
            print(f"  gcloud CLI 토큰 획득 성공")
        except Exception as e2:
            print(f"  인증 완전 실패: {e2}")
            sys.exit(1)

    # 2. 배경 이미지 생성
    print("\n[Step 1] Gemini 배경 이미지 생성")
    start = time.time()
    success = generate_bg_image(token)

    if not success:
        print("  Gemini 이미지 생성 실패. 폴백: 크림 그라디언트 배경 생성...")
        # 폴백: Python으로 직접 배경 이미지 생성
        _generate_fallback_bg()
        success = BG_PATH.exists()

    if not success:
        print("배경 생성 완전 실패. 종료.")
        sys.exit(1)

    elapsed = time.time() - start
    print(f"  소요 시간: {elapsed:.1f}초")

    # 3. HTML 렌더링
    print("\n[Step 2] HTML 오버레이 합성 (Playwright)")
    render_html_to_png(BG_PATH)

    # 4. 검증
    print("\n[검증]")
    verify_output()

    print("\n" + "=" * 60)
    print("생성 완료!")
    print(f"  배경:    {BG_PATH}")
    print(f"  템플릿:  {TEMPLATE_PATH}")
    print(f"  최종:    {SAMPLE_PATH}")
    print("=" * 60)


def _generate_fallback_bg() -> None:
    """Pillow로 따뜻한 크림 그라디언트 배경을 생성합니다 (Gemini 실패 시 폴백)."""
    try:
        from PIL import Image, ImageDraw, ImageFilter
        import random

        print("  [폴백] Pillow로 크림 파스텔 배경 생성...")
        img = Image.new("RGB", (1080, 1080))
        draw = ImageDraw.Draw(img)

        # 크림-앰버 그라디언트
        for y in range(1080):
            t = y / 1080
            r = int(255 - t * 30)
            g = int(248 - t * 60)
            b = int(220 - t * 100)
            draw.line([(0, y), (1080, y)], fill=(r, g, b))

        # 부드러운 블러로 자연스러운 느낌
        img = img.filter(ImageFilter.GaussianBlur(radius=3))
        img.save(str(BG_PATH), "JPEG", quality=95)
        print(f"  [OK] 폴백 배경 저장: {BG_PATH}")
    except ImportError:
        # Pillow도 없으면 단색 JPEG 생성
        _generate_solid_bg()


def _generate_solid_bg() -> None:
    """최소한의 단색 배경 JPEG 생성 (최후 폴백)."""
    import struct, zlib

    # 간단한 단색 PPM → 저장
    w, h = 1080, 1080
    # Cream color #FFF8DC = (255, 248, 220)
    r, g, b = 255, 248, 220

    # 최소 JPEG 생성을 위해 netpbm PPM 방식 대신 PIL 없이는 어렵므로
    # 대신 HTML canvas 방식으로 배경 없이 렌더링
    print("  [폴백] 배경 이미지 없이 단색 배경으로 렌더링합니다.")
    # BG_PATH를 None으로 처리할 수 없으므로 임시 단색 PNG 생성
    # PNG 헤더 최소 구조
    def create_solid_png(path: Path, color: tuple, size: tuple) -> None:
        from PIL import Image
        img = Image.new("RGB", size, color)
        img.save(str(path), "JPEG", quality=95)

    try:
        create_solid_png(BG_PATH, (r, g, b), (w, h))
    except Exception:
        pass


if __name__ == "__main__":
    main()
