#!/usr/bin/env python3
"""컨셉 #16 네이비 타이포 임팩트 v2 생성 스크립트.

1. Gemini API로 배경(딥 네이비 단색 텍스처) 생성
2. HTML 템플릿 + Playwright로 텍스트 오버레이 합성
3. sample-v2.png 및 16-navy-typography-v2.png 저장
"""

from __future__ import annotations

import base64
import shutil
import sys
import time
from pathlib import Path

import requests

# 프로젝트 루트를 sys.path에 추가 (gcloud_auth 임포트)
SCRIPT_DIR = Path(__file__).parent
sys.path.insert(0, str(SCRIPT_DIR))
import gcloud_auth

# ─── 경로 설정 ───────────────────────────────────────────────────────────────
OUTPUT_DIR = Path("/home/jay/workspace/output/meta-ads/concept-catalog/16-navy-typography")
TEMPLATE_PATH = OUTPUT_DIR / "template-v2.html"
BG_PATH = OUTPUT_DIR / "bg_v2.jpg"
SAMPLE_V2_PATH = OUTPUT_DIR / "sample-v2.png"
COPY_PATH = OUTPUT_DIR / "16-navy-typography-v2.png"

# ─── Gemini API 설정 ──────────────────────────────────────────────────────────
GEMINI_API_BASE = "https://generativelanguage.googleapis.com/v1beta"
GEMINI_SCOPE = "https://www.googleapis.com/auth/generative-language"

# 배경 이미지 생성 프롬프트
BG_PROMPT = (
    "Deep navy blue solid color background, professional corporate aesthetic, "
    "very subtle dark blue diagonal line texture, no people, no text, "
    "slight vignette at edges, authoritative financial services mood, "
    "1080x1080, minimal clean dark navy blue, rich deep color, "
    "luxury corporate background, no gradients overpowering the navy, "
    "photorealistic texture"
)


def generate_bg_with_api_key() -> bytes | None:
    """API 키로 Gemini 이미지 생성 시도."""
    api_key = gcloud_auth.get_api_key("GEMINI_API_KEY")
    if not api_key:
        print("  [API Key] GEMINI_API_KEY 없음, 스킵")
        return None

    # 1순위: imagen-4.0-generate-001 (predict 방식)
    for imagen_model in ["imagen-4.0-generate-001", "imagen-4.0-fast-generate-001"]:
        url = f"{GEMINI_API_BASE}/models/{imagen_model}:predict?key={api_key}"
        payload = {
            "instances": [{"prompt": BG_PROMPT}],
            "parameters": {
                "sampleCount": 1,
                "aspectRatio": "1:1",
                "outputMimeType": "image/jpeg",
            },
        }
        print(f"  [API Key] {imagen_model} 요청 중...")
        try:
            resp = requests.post(url, json=payload, timeout=120)
            if resp.status_code == 200:
                data = resp.json()
                predictions = data.get("predictions", [])
                if predictions and "bytesBase64Encoded" in predictions[0]:
                    img_bytes = base64.b64decode(predictions[0]["bytesBase64Encoded"])
                    print(f"  [API Key] {imagen_model} 성공! ({len(img_bytes):,} bytes)")
                    return img_bytes
                print(f"  [API Key] {imagen_model} 응답에 이미지 없음: {str(data)[:200]}")
            else:
                print(f"  [API Key] {imagen_model} HTTP {resp.status_code}: {resp.text[:200]}")
        except Exception as e:
            print(f"  [API Key] {imagen_model} 오류: {e}")

    # 2순위: gemini generateContent 이미지 모달리티
    for model_id in [
        "gemini-2.0-flash-preview-image-generation",
        "gemini-3-pro-image-preview",
        "gemini-3.1-flash-image-preview",
        "gemini-2.5-flash-image",
    ]:
        url = f"{GEMINI_API_BASE}/models/{model_id}:generateContent?key={api_key}"
        payload = {
            "contents": [{"parts": [{"text": BG_PROMPT}]}],
            "generationConfig": {"responseModalities": ["IMAGE", "TEXT"]},
        }
        print(f"  [API Key] {model_id} 요청 중...")
        try:
            resp = requests.post(url, json=payload, timeout=120)
            if resp.status_code == 200:
                data = resp.json()
                candidates = data.get("candidates", [])
                for cand in candidates:
                    parts = cand.get("content", {}).get("parts", [])
                    for part in parts:
                        if "inlineData" in part:
                            img_bytes = base64.b64decode(part["inlineData"]["data"])
                            print(f"  [API Key] {model_id} 성공! ({len(img_bytes):,} bytes)")
                            return img_bytes
                print(f"  [API Key] {model_id} 응답에 이미지 없음")
            else:
                print(f"  [API Key] {model_id} HTTP {resp.status_code}: {resp.text[:150]}")
        except Exception as e:
            print(f"  [API Key] {model_id} 오류: {e}")

    return None


def generate_bg_with_token(token: str) -> bytes | None:
    """Bearer 토큰으로 Gemini 이미지 생성 시도."""
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }

    for model_id in [
        "gemini-2.0-flash-preview-image-generation",
        "gemini-3-pro-image-preview",
        "gemini-3.1-flash-image-preview",
        "gemini-2.5-flash-image",
    ]:
        url = f"{GEMINI_API_BASE}/models/{model_id}:generateContent"
        payload = {
            "contents": [{"parts": [{"text": BG_PROMPT}]}],
            "generationConfig": {"responseModalities": ["IMAGE", "TEXT"]},
        }
        print(f"  [Bearer] {model_id} 요청 중...")
        try:
            resp = requests.post(url, headers=headers, json=payload, timeout=120)
            if resp.status_code == 200:
                data = resp.json()
                candidates = data.get("candidates", [])
                for cand in candidates:
                    parts = cand.get("content", {}).get("parts", [])
                    for part in parts:
                        if "inlineData" in part:
                            img_bytes = base64.b64decode(part["inlineData"]["data"])
                            print(f"  [Bearer] {model_id} 성공! ({len(img_bytes):,} bytes)")
                            return img_bytes
                print(f"  [Bearer] {model_id} 응답에 이미지 없음")
            else:
                print(f"  [Bearer] {model_id} HTTP {resp.status_code}: {resp.text[:150]}")
        except Exception as e:
            print(f"  [Bearer] {model_id} 오류: {e}")

    # imagen-4.0 with Bearer
    for imagen_model in ["imagen-4.0-generate-001", "imagen-4.0-fast-generate-001"]:
        url = f"{GEMINI_API_BASE}/models/{imagen_model}:predict"
        payload = {
            "instances": [{"prompt": BG_PROMPT}],
            "parameters": {
                "sampleCount": 1,
                "aspectRatio": "1:1",
                "outputMimeType": "image/jpeg",
            },
        }
        print(f"  [Bearer] {imagen_model} 요청 중...")
        try:
            resp = requests.post(url, headers=headers, json=payload, timeout=120)
            if resp.status_code == 200:
                data = resp.json()
                predictions = data.get("predictions", [])
                if predictions and "bytesBase64Encoded" in predictions[0]:
                    img_bytes = base64.b64decode(predictions[0]["bytesBase64Encoded"])
                    print(f"  [Bearer] {imagen_model} 성공! ({len(img_bytes):,} bytes)")
                    return img_bytes
            print(f"  [Bearer] {imagen_model} HTTP {resp.status_code}: {resp.text[:150]}")
        except Exception as e:
            print(f"  [Bearer] {imagen_model} 오류: {e}")

    return None


def generate_background() -> Path:
    """배경 이미지 생성. 성공 시 저장 경로 반환."""
    print("\n[1단계] 배경 이미지 생성 시작")
    start = time.time()

    # 이미 bg_v2.jpg가 있으면 재사용
    if BG_PATH.exists():
        print(f"  기존 bg_v2.jpg 재사용: {BG_PATH}")
        return BG_PATH

    # 1순위: API 키
    img_bytes = generate_bg_with_api_key()

    # 2순위: Bearer 토큰
    if img_bytes is None:
        print("  [Bearer 토큰] SA 토큰 획득 중...")
        try:
            token = gcloud_auth.get_service_account_token(GEMINI_SCOPE)
            img_bytes = generate_bg_with_token(token)
        except Exception as e:
            print(f"  [Bearer 토큰] 실패: {e}")

    if img_bytes is None:
        print("  [경고] Gemini API 배경 생성 실패 — CSS 단색 네이비로 폴백합니다")
        return None  # type: ignore[return-value]

    BG_PATH.write_bytes(img_bytes)
    elapsed = time.time() - start
    print(f"  bg_v2.jpg 저장 완료: {BG_PATH} ({len(img_bytes):,} bytes, {elapsed:.1f}초)")
    return BG_PATH


def capture_overlay(bg_path: Path | None, output_path: Path) -> None:
    """Playwright로 HTML 오버레이 캡처."""
    from playwright.sync_api import sync_playwright

    print(f"\n[2단계] HTML 오버레이 합성 → {output_path.name}")

    if not TEMPLATE_PATH.exists():
        raise FileNotFoundError(f"템플릿 없음: {TEMPLATE_PATH}")

    template_url = f"file://{TEMPLATE_PATH.resolve()}"

    with sync_playwright() as p:
        browser = p.chromium.launch()
        try:
            page = browser.new_page(viewport={"width": 1080, "height": 1080})
            page.goto(template_url, wait_until="networkidle")

            # 배경 이미지 주입 (있을 때만)
            if bg_path is not None and bg_path.exists():
                bg_file_url = f"file://{bg_path.resolve()}"
                page.evaluate(f"""() => {{
                    const bgEl = document.getElementById('bgImage');
                    if (bgEl) {{
                        bgEl.style.backgroundImage = "url('{bg_file_url}')";
                    }}
                }}""")
                print(f"  배경 이미지 적용: {bg_path.name}")
            else:
                print("  배경 이미지 없음 — CSS 단색 네이비 사용")

            # 폰트 및 렌더링 완료 대기
            page.evaluate("() => document.fonts.ready")
            page.wait_for_timeout(2000)

            output_path.parent.mkdir(parents=True, exist_ok=True)
            page.screenshot(
                path=str(output_path),
                type="png",
                clip={"x": 0, "y": 0, "width": 1080, "height": 1080},
            )
            print(f"  캡처 완료: {output_path}")
        finally:
            browser.close()


def main() -> None:
    print("=" * 60)
    print("컨셉 #16 네이비 타이포 임팩트 v2 생성")
    print("=" * 60)

    # 1. 배경 이미지 생성
    bg_path = generate_background()

    # 2. HTML 오버레이 합성 → sample-v2.png
    capture_overlay(bg_path, SAMPLE_V2_PATH)

    # 3. 파일 복사 → 16-navy-typography-v2.png
    print(f"\n[3단계] 파일 복사: {COPY_PATH.name}")
    shutil.copy2(SAMPLE_V2_PATH, COPY_PATH)
    print(f"  복사 완료: {COPY_PATH}")

    # 결과 출력
    print("\n" + "=" * 60)
    print("생성 완료")
    print("=" * 60)
    for p in [SAMPLE_V2_PATH, COPY_PATH]:
        if p.exists():
            size_kb = p.stat().st_size / 1024
            print(f"  {p} ({size_kb:.0f} KB)")


if __name__ == "__main__":
    main()
