#!/usr/bin/env python3
"""컨셉 #35 (Bottom-Anchored Content Stack) 프로덕션 배너 생성기
- c35-1200x628.png  (가로형, Meta/Google Ads)
- c35-1200x1200.png (정사각형, Meta Ads)
- c35-1200x628.html
- c35-1200x1200.html

디자인:
- Gemini 야경 사무실 배경
- 하단 네이비 그라디언트 오버레이
- Pretendard 900 헤드라인 + 오렌지 키워드 하이라이트
- 프로스티드 글라스 서브카피 블록 (blur 20px)
- 오렌지 아웃라인 CTA 필 버튼
"""

from __future__ import annotations

import base64
import json
import sys
from pathlib import Path

import requests
from playwright.sync_api import sync_playwright
from gen_config import CORE_METRIC_MIN_PX, CTA_MIN_PX, FONT_DIR, HEAD_SUB_RATIO, WORKSPACE_ROOT

# ── 디자인 토큰 ──
_CTA_PX = CTA_MIN_PX
_SIZE_44PX = 44
_SIZE_54PX = 54
_SIZE_68PX = 68
_METRIC_PX = CORE_METRIC_MIN_PX
_LH_1_15 = 1.15
_LH_1_2 = 1.2
_LH_RATIO = HEAD_SUB_RATIO


# ── 경로 설정 ────────────────────────────────────────────────────────────────
BASE_DIR = Path(__file__).parent
OUTPUT_DIR = WORKSPACE_ROOT / "output/meta-ads/production-banners/35-hybrid-v4-refined-A"
TMP_DIR = BASE_DIR / "output" / "v4-hybrid"

BG_LANDSCAPE_PATH = TMP_DIR / "bg_c35_landscape.jpg"   # 1200x628용
BG_SQUARE_PATH    = TMP_DIR / "bg_c35_square.jpg"      # 1200x1200용

# ── Gemini API 설정 ───────────────────────────────────────────────────────────
GEMINI_API_BASE  = "https://generativelanguage.googleapis.com/v1beta"
MODEL_ID         = "gemini-3-pro-image-preview"
FALLBACK_MODEL   = "gemini-3.1-flash-image-preview"

# ── 배경 프롬프트 ─────────────────────────────────────────────────────────────
BG_PROMPT_LANDSCAPE = (
    "Modern Korean office interior at night, dark and moody atmosphere, "
    "a desk with a laptop, large window showing city lights in the background, "
    "soft ambient lighting from monitors, cool blue-grey color grading, "
    "cinematic depth of field, photorealistic, no people, no text, no logos. "
    "Wide landscape composition 16:9 aspect ratio, the lower half darker "
    "for text overlay."
)

BG_PROMPT_SQUARE = (
    "Modern Korean office interior at night, dark and moody atmosphere, "
    "a desk with a laptop, large window showing city lights in the background, "
    "soft ambient lighting from monitors, cool blue-grey color grading, "
    "cinematic depth of field, photorealistic, no people, no text, no logos. "
    "Square composition, the lower half significantly darker for text overlay."
)


# ── Auth helpers ──────────────────────────────────────────────────────────────

def get_auth_token() -> str:
    sys.path.insert(0, str(BASE_DIR))
    import gcloud_auth
    return gcloud_auth.get_access_token()


def get_api_key() -> str | None:
    sys.path.insert(0, str(BASE_DIR))
    import gcloud_auth as ga
    return ga.get_api_key("GEMINI_API_KEY")


def _call_model(token: str, api_key: str | None, model: str, payload: dict) -> requests.Response:
    url_bearer = f"{GEMINI_API_BASE}/models/{model}:generateContent"
    headers    = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
    resp = requests.post(url_bearer, headers=headers, json=payload, timeout=300)
    if resp.status_code == 200:
        return resp
    if api_key:
        url_key  = f"{GEMINI_API_BASE}/models/{model}:generateContent?key={api_key}"
        hdrs_key = {"Content-Type": "application/json"}
        return requests.post(url_key, headers=hdrs_key, json=payload, timeout=300)
    return resp


def generate_background(prompt: str, out_path: Path) -> Path:
    """Gemini API로 배경 이미지를 생성합니다. 이미 존재하면 재사용합니다."""
    if out_path.exists() and out_path.stat().st_size > 50_000:
        print(f"  [배경] 기존 재사용: {out_path}")
        return out_path

    print(f"  [배경] Gemini API 생성 중: {out_path.name}")
    token   = get_auth_token()
    api_key = get_api_key()

    payload = {
        "contents": [{"parts": [{"text": prompt}]}],
        "generationConfig": {"responseModalities": ["IMAGE", "TEXT"]},
    }

    for model in [MODEL_ID, FALLBACK_MODEL]:
        print(f"    모델: {model}")
        try:
            resp = _call_model(token, api_key, model, payload)
        except Exception as e:
            print(f"    요청 예외: {e}")
            continue

        if resp.status_code in (400, 403, 404):
            print(f"    접근 불가 ({resp.status_code}): {resp.text[:150]}")
            continue
        if resp.status_code != 200:
            print(f"    HTTP {resp.status_code}: {resp.text[:200]}")
            continue

        data       = resp.json()
        candidates = data.get("candidates", [])
        if not candidates:
            print(f"    candidates 없음")
            continue

        parts      = candidates[0].get("content", {}).get("parts", [])
        img_part   = next((p for p in parts if "inlineData" in p), None)
        if img_part is None:
            print(f"    이미지 파트 없음")
            continue

        img_bytes = base64.b64decode(img_part["inlineData"]["data"])
        out_path.parent.mkdir(parents=True, exist_ok=True)
        out_path.write_bytes(img_bytes)
        print(f"    저장 완료: {out_path} ({len(img_bytes):,} bytes)")
        return out_path

    raise RuntimeError(f"배경 생성 실패: {out_path.name}")


# ── HTML 생성 ─────────────────────────────────────────────────────────────────

FONT_FACES = """
  @font-face {
    font-family: 'Pretendard';
    src: url('file://{FONT_DIR}/Pretendard-Black.otf') format('opentype');
    font-weight: 900;
    font-style: normal;
  }
  @font-face {
    font-family: 'Pretendard';
    src: url('file://{FONT_DIR}/Pretendard-ExtraBold.otf') format('opentype');
    font-weight: 800;
    font-style: normal;
  }
  @font-face {
    font-family: 'Pretendard';
    src: url('file://{FONT_DIR}/Pretendard-Bold.otf') format('opentype');
    font-weight: 700;
    font-style: normal;
  }
"""


def make_html_1200x628(bg_path: Path) -> str:
    """1200x628 가로형 배너 HTML."""
    bg_uri = f"file://{bg_path.resolve()}"
    return f"""<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<style>
{FONT_FACES}

  * {{ margin: 0; padding: 0; box-sizing: border-box; }}

  body {{
    width: 1200px;
    height: 628px;
    overflow: hidden;
    font-family: 'Pretendard', sans-serif;
    background: #001E3C;
  }}

  .card {{
    position: relative;
    width: 1200px;
    height: 628px;
    overflow: hidden;
  }}

  /* 배경 포토 */
  .bg-photo {{
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center center;
  }}

  /* 하단 그라디언트 오버레이 (50% 높이 = 314px) */
  .gradient-overlay {{
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 314px;
    background: linear-gradient(
      to bottom,
      transparent 0%,
      rgba(0, 30, 60, 0.55) 40%,
      rgba(0, 30, 60, 0.88) 100%
    );
  }}

  /* 콘텐츠 스택 (하단 좌측 앵커) */
  .content-stack {{
    position: absolute;
    bottom: 48px;
    left: 56px;
    right: 56px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 20px;
  }}

  /* 메인 헤드라인 */
  .headline {{
    font-size: {_SIZE_54PX}px;
    font-weight: 900;
    color: #FFFFFF;
    line-height: {_LH_1_2};
    letter-spacing: -1.2px;
    word-break: keep-all;
    text-shadow:
      0 2px 8px rgba(0, 0, 0, 0.70),
      0 4px 24px rgba(0, 30, 60, 0.60);
  }}

  .headline .highlight {{
    color: #EA580C;
  }}

  /* 프로스티드 글라스 서브카피 블록 */
  .sub-copy-block {{
    background: rgba(0, 30, 60, 0.45);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border: 1px solid rgba(255, 255, 255, 0.18);
    box-shadow:
      0 4px 32px rgba(0, 30, 60, 0.35),
      inset 0 1px 0 rgba(255, 255, 255, 0.12);
    border-radius: 16px;
    padding: 18px 28px;
  }}

  .sub-copy-text {{
    font-size: {_SIZE_44PX}px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
    line-height: {_LH_RATIO};
    letter-spacing: -0.5px;
    word-break: keep-all;
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.50);
  }}

  /* CTA 필 버튼 */
  .cta-pill {{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 14px 40px;
    border: 2.5px solid #EA580C;
    border-radius: 9999px;
    background: transparent;
    font-size: {_CTA_PX}px;
    font-weight: 800;
    color: #EA580C;
    letter-spacing: -0.3px;
    white-space: nowrap;
  }}
</style>
</head>
<body>
<div class="card">

  <!-- 배경 포토 -->
  <img class="bg-photo" src="{bg_uri}" alt="background">

  <!-- 하단 그라디언트 오버레이 -->
  <div class="gradient-overlay"></div>

  <!-- 콘텐츠 스택 (하단 좌측 앵커) -->
  <div class="content-stack">

    <!-- 메인 헤드라인 -->
    <div class="headline">
      열심히는 하는데,<br>
      소득은 <span class="highlight">제자리걸음?</span>
    </div>

    <!-- 프로스티드 글라스 서브카피 블록 -->
    <div class="sub-copy-block">
      <div class="sub-copy-text">정착지원금이 시작을 바꿉니다</div>
    </div>

    <!-- CTA 필 버튼 -->
    <div class="cta-pill">지금 조건 확인하기 →</div>

  </div>
</div>
</body>
</html>"""


def make_html_1200x1200(bg_path: Path) -> str:
    """1200x1200 정사각형 배너 HTML."""
    bg_uri = f"file://{bg_path.resolve()}"
    return f"""<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<style>
{FONT_FACES}

  * {{ margin: 0; padding: 0; box-sizing: border-box; }}

  body {{
    width: 1200px;
    height: 1200px;
    overflow: hidden;
    font-family: 'Pretendard', sans-serif;
    background: #001E3C;
  }}

  .card {{
    position: relative;
    width: 1200px;
    height: 1200px;
    overflow: hidden;
  }}

  /* 배경 포토 */
  .bg-photo {{
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center center;
  }}

  /* 하단 그라디언트 오버레이 (50% 높이 = 600px) */
  .gradient-overlay {{
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 600px;
    background: linear-gradient(
      to bottom,
      transparent 0%,
      rgba(0, 30, 60, 0.55) 40%,
      rgba(0, 30, 60, 0.88) 100%
    );
  }}

  /* 콘텐츠 스택 (하단 앵커) */
  .content-stack {{
    position: absolute;
    bottom: 72px;
    left: 64px;
    right: 64px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 28px;
  }}

  /* 메인 헤드라인 */
  .headline {{
    font-size: {_METRIC_PX}px;
    font-weight: 900;
    color: #FFFFFF;
    line-height: {_LH_1_15};
    letter-spacing: -1.8px;
    word-break: keep-all;
    text-shadow:
      0 2px 8px rgba(0, 0, 0, 0.70),
      0 4px 24px rgba(0, 30, 60, 0.60);
  }}

  .headline .highlight {{
    color: #EA580C;
  }}

  /* 프로스티드 글라스 서브카피 블록 */
  .sub-copy-block {{
    background: rgba(0, 30, 60, 0.45);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border: 1px solid rgba(255, 255, 255, 0.18);
    box-shadow:
      0 4px 32px rgba(0, 30, 60, 0.35),
      inset 0 1px 0 rgba(255, 255, 255, 0.12);
    border-radius: 16px;
    padding: 28px 40px;
    align-self: stretch;
  }}

  .sub-copy-text {{
    font-size: {_SIZE_68PX}px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
    line-height: {_LH_RATIO};
    letter-spacing: -0.8px;
    word-break: keep-all;
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.50);
  }}

  /* CTA 필 버튼 */
  .cta-pill {{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 18px 52px;
    border: 2.5px solid #EA580C;
    border-radius: 9999px;
    background: transparent;
    font-size: {_SIZE_44PX}px;
    font-weight: 800;
    color: #EA580C;
    letter-spacing: -0.3px;
    white-space: nowrap;
  }}
</style>
</head>
<body>
<div class="card">

  <!-- 배경 포토 -->
  <img class="bg-photo" src="{bg_uri}" alt="background">

  <!-- 하단 그라디언트 오버레이 -->
  <div class="gradient-overlay"></div>

  <!-- 콘텐츠 스택 (하단 앵커) -->
  <div class="content-stack">

    <!-- 메인 헤드라인 -->
    <div class="headline">
      열심히는 하는데,<br>
      소득은 <span class="highlight">제자리걸음?</span>
    </div>

    <!-- 프로스티드 글라스 서브카피 블록 -->
    <div class="sub-copy-block">
      <div class="sub-copy-text">정착지원금이 시작을 바꿉니다</div>
    </div>

    <!-- CTA 필 버튼 -->
    <div class="cta-pill">지금 조건 확인하기 →</div>

  </div>
</div>
</body>
</html>"""


# ── Playwright 캡처 ───────────────────────────────────────────────────────────

def capture_html_to_png(html_content: str, html_save_path: Path,
                         width: int, height: int, png_path: Path) -> None:
    """HTML을 파일로 저장한 뒤 Playwright로 PNG 캡처합니다."""
    html_save_path.parent.mkdir(parents=True, exist_ok=True)
    html_save_path.write_text(html_content, encoding="utf-8")
    print(f"  [HTML] 저장: {html_save_path}")

    with sync_playwright() as p:
        browser = p.chromium.launch()
        try:
            page = browser.new_page(viewport={"width": width, "height": height})
            page.goto(f"file://{html_save_path.resolve()}", wait_until="networkidle")
            page.wait_for_timeout(2500)   # 폰트 + backdrop-filter 렌더링 대기
            png_path.parent.mkdir(parents=True, exist_ok=True)
            page.screenshot(path=str(png_path), type="png", clip={
                "x": 0, "y": 0, "width": width, "height": height
            })
            kb = png_path.stat().st_size / 1024
            print(f"  [PNG] 캡처 완료: {png_path} ({kb:.0f} KB)")
        finally:
            browser.close()


# ── 메인 ─────────────────────────────────────────────────────────────────────

def main() -> None:
    print("=" * 64)
    print("컨셉 #35 프로덕션 배너 생성 시작")
    print("=" * 64)

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

    results: dict[str, str] = {}

    # ── 1. 1200x628 배너 ────────────────────────────────────────────────────
    print("\n[1/2] 1200x628 가로형 배너")

    try:
        bg_land = generate_background(BG_PROMPT_LANDSCAPE, BG_LANDSCAPE_PATH)
    except Exception as e:
        print(f"  [경고] 배경 생성 실패: {e}")
        print("  [폴백] 기존 bg.png (1024×1024) 사용")
        bg_land = WORKSPACE_ROOT / "output/meta-ads/concept-catalog/35-hybrid-v4-refined-A/bg.png"

    html_1200x628 = make_html_1200x628(bg_land)
    html_out_628  = OUTPUT_DIR / "c35-1200x628.html"
    png_out_628   = OUTPUT_DIR / "c35-1200x628.png"
    try:
        capture_html_to_png(html_1200x628, html_out_628, 1200, 628, png_out_628)
        results["1200x628_png"]  = str(png_out_628)
        results["1200x628_html"] = str(html_out_628)
    except Exception as e:
        print(f"  [오류] 1200x628 캡처 실패: {e}")
        results["1200x628_error"] = str(e)

    # ── 2. 1200x1200 배너 ───────────────────────────────────────────────────
    print("\n[2/2] 1200x1200 정사각형 배너")

    try:
        bg_sq = generate_background(BG_PROMPT_SQUARE, BG_SQUARE_PATH)
    except Exception as e:
        print(f"  [경고] 배경 생성 실패: {e}")
        print("  [폴백] 기존 bg.png (1024×1024) 사용")
        bg_sq = WORKSPACE_ROOT / "output/meta-ads/concept-catalog/35-hybrid-v4-refined-A/bg.png"

    html_1200x1200 = make_html_1200x1200(bg_sq)
    html_out_1200  = OUTPUT_DIR / "c35-1200x1200.html"
    png_out_1200   = OUTPUT_DIR / "c35-1200x1200.png"
    try:
        capture_html_to_png(html_1200x1200, html_out_1200, 1200, 1200, png_out_1200)
        results["1200x1200_png"]  = str(png_out_1200)
        results["1200x1200_html"] = str(html_out_1200)
    except Exception as e:
        print(f"  [오류] 1200x1200 캡처 실패: {e}")
        results["1200x1200_error"] = str(e)

    # ── 결과 요약 ───────────────────────────────────────────────────────────
    print("\n" + "=" * 64)
    print("생성 결과:")
    for key, val in results.items():
        status = "OK" if "error" not in key else "FAIL"
        print(f"  [{status}] {key}: {val}")
    print("=" * 64)


if __name__ == "__main__":
    main()
