#!/usr/bin/env python3
"""
sample-A-portrait: 인물+텍스트 하이브리드 광고 배너 생성
- 배경: Gemini AI (비즈니스 정장 한국인 남성, 사무실, 우측 인물)
- 텍스트: HTML/CSS + Playwright
- 출력: /home/jay/workspace/output/meta-ads/angle-A/concept-samples/sample-A-portrait.png
"""

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

import requests
from playwright.sync_api import sync_playwright
from gen_config import WORKSPACE_ROOT, FONT_DIR, SUBHEAD_MIN_PX

sys.path.insert(0, str(Path(__file__).parent))
import gcloud_auth
_SIZE_22PX = 22
_SIZE_28PX = 28
_SIZE_30PX = 30
_SIZE_32PX = 32
_SUBHEAD_PX = SUBHEAD_MIN_PX
_LH_1_18 = 1.18
_LH_1_6 = 1.6

# ─────────────────────────────────────────────────────────────────────
# 설정
# ─────────────────────────────────────────────────────────────────────

OUTPUT_DIR = WORKSPACE_ROOT / "output/meta-ads/angle-A/concept-samples"
BG_PATH = OUTPUT_DIR / "sample-A-portrait-bg.jpg"
FINAL_PATH = OUTPUT_DIR / "sample-A-portrait.png"

MODEL_ID = "gemini-3.1-flash-image-preview"
GEMINI_API_BASE = "https://generativelanguage.googleapis.com/v1beta"
GEMINI_SCOPE = "https://www.googleapis.com/auth/generative-language"

BG_PROMPT = (
    "Premium photo-realistic advertisement background for Meta ads. "
    "Korean male in his 30s wearing a sharp navy business suit, confident expression, "
    "slight smile, looking slightly off-camera. Subject positioned on the RIGHT THIRD of the frame. "
    "LEFT HALF of the image must be intentionally blurred/clean dark navy background — "
    "this space is reserved for text overlay. "
    "Setting: modern high-rise office, Seoul skyline visible through large windows behind. "
    "Lighting: premium studio-style, warm key light from upper-right, subtle rim light. "
    "Color palette: deep navy (#1B2A4A dominant), warm whites, subtle gold accents. "
    "Camera: 85mm portrait lens, shallow depth of field, background softly bokeh'd. "
    "Style: like a premium financial services advertisement (Merrill Lynch / Goldman Sachs quality). "
    "NO text, NO watermark, NO clipart. 1:1 square format 1080x1080px."
)

HTML_TEMPLATE = f"""<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=1080" />
  <style>
    @import url('file://{FONT_DIR}/pretendard.css');

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

    html, body {{
      width: 1080px;
      height: 1080px;
      overflow: hidden;
      -webkit-font-smoothing: antialiased;
      font-family: 'Pretendard', 'Noto Sans KR', 'Apple SD Gothic Neo', sans-serif;
    }}

    /* 배경 레이어 */
    #bg {{
      position: absolute;
      inset: 0;
      background-image: url('{bg_url}');
      background-size: cover;
      background-position: center center;
      z-index: 0;
    }}

    /* 좌측 텍스트 영역 어둠 강화 오버레이 */
    #left-overlay {{
      position: absolute;
      top: 0; left: 0;
      width: 560px; height: 1080px;
      background: linear-gradient(
        90deg,
        rgba(27, 42, 74, 0.92) 0%,
        rgba(27, 42, 74, 0.82) 70%,
        rgba(27, 42, 74, 0.0) 100%
      );
      z-index: 1;
    }}

    /* 전체 미묘한 비네트 */
    #vignette {{
      position: absolute;
      inset: 0;
      background: radial-gradient(
        ellipse at 30% 50%,
        transparent 30%,
        rgba(10, 15, 30, 0.45) 100%
      );
      z-index: 2;
      pointer-events: none;
    }}

    /* 텍스트 콘텐츠 래퍼 */
    #content {{
      position: absolute;
      inset: 0;
      z-index: 10;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      padding: 72px 60px 72px 72px;
    }}

    /* 상단 영역: 메인 헤드라인 */
    .top-section {{
      display: flex;
      flex-direction: column;
      gap: 0;
      max-width: 520px;
    }}

    /* 오렌지 상단 액센트 바 */
    .accent-bar {{
      width: 52px;
      height: 5px;
      background: #FF6B35;
      border-radius: 3px;
      margin-bottom: 28px;
    }}

    /* 메인 헤드라인 */
    .headline {{
      font-size: {_SUBHEAD_PX}px;
      font-weight: 900;
      line-height: {_LH_1_18};
      letter-spacing: -0.03em;
      color: #FFFFFF;
      word-break: keep-all;
      text-shadow:
        0 2px 12px rgba(0, 0, 0, 0.50),
        0 4px 40px rgba(0, 0, 0, 0.30);
    }}

    /* 헤드라인 내 오렌지 강조 */
    .headline .highlight {{
      color: #FF6B35;
    }}

    /* 중간 서브 메시지 */
    .sub-message {{
      margin-top: 32px;
      font-size: {_SIZE_28PX}px;
      font-weight: 400;
      line-height: {_LH_1_6};
      color: rgba(255, 255, 255, 0.78);
      word-break: keep-all;
      max-width: 480px;
      letter-spacing: -0.01em;
    }}

    /* 하단 CTA 영역 */
    .bottom-section {{
      display: flex;
      flex-direction: column;
      gap: 20px;
      max-width: 520px;
    }}

    /* CTA 버튼 스타일 */
    .cta-button {{
      display: inline-flex;
      align-items: center;
      gap: 12px;
      background: #FF6B35;
      color: #FFFFFF;
      font-size: {_SIZE_30PX}px;
      font-weight: 800;
      padding: 22px 40px;
      border-radius: 8px;
      letter-spacing: -0.02em;
      word-break: keep-all;
      align-self: flex-start;
      box-shadow:
        0 4px 24px rgba(255, 107, 53, 0.45),
        0 2px 8px rgba(0, 0, 0, 0.30);
    }}

    .cta-arrow {{
      font-size: {_SIZE_32PX}px;
      font-weight: 900;
    }}

    /* 브랜드명 */
    .brand {{
      font-size: {_SIZE_22PX}px;
      font-weight: 500;
      color: rgba(255, 255, 255, 0.50);
      letter-spacing: 0.06em;
      text-transform: uppercase;
    }}
  </style>
</head>
<body>

  <!-- 배경 -->
  <div id="bg"></div>

  <!-- 좌측 어둠 오버레이 (텍스트 가독성) -->
  <div id="left-overlay"></div>

  <!-- 비네트 -->
  <div id="vignette"></div>

  <!-- 텍스트 콘텐츠 -->
  <div id="content">

    <!-- 상단: 메인 헤드라인 -->
    <div class="top-section">
      <div class="accent-bar"></div>
      <div class="headline">
        열심히는 하는데,<br>
        <span class="highlight">월급은</span><br>
        제자리걸음?
      </div>
      <div class="sub-message">
        노력한 만큼 보상받는<br>방법이 따로 있습니다.
      </div>
    </div>

    <!-- 하단: CTA -->
    <div class="bottom-section">
      <div class="cta-button">
        다른 방법이 있다는 걸 아세요?
        <span class="cta-arrow">→</span>
      </div>
      <div class="brand">Premium Career Solution</div>
    </div>

  </div>

</body>
</html>"""


# ─────────────────────────────────────────────────────────────────────
# Step 1: Gemini API로 배경 이미지 생성
# ─────────────────────────────────────────────────────────────────────

def generate_background() -> Path:
    print("[Step 1] Gemini API로 배경 이미지 생성 중...")

    # SA 토큰 우선, 실패 시 API 키 fallback
    token = None
    api_key = None

    try:
        token = gcloud_auth.get_service_account_token(GEMINI_SCOPE)
        print(f"  인증: SA 토큰 사용 (len={len(token)})")
        url = f"{GEMINI_API_BASE}/models/{MODEL_ID}:generateContent"
        headers = {
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json",
        }
    except Exception as e:
        print(f"  SA 토큰 실패: {e}. API 키로 fallback...")
        api_key = gcloud_auth.get_api_key("GEMINI_API_KEY")
        if not api_key:
            raise RuntimeError("SA 토큰과 API 키 모두 사용 불가")
        print(f"  인증: API 키 사용 (len={len(api_key)})")
        url = f"{GEMINI_API_BASE}/models/{MODEL_ID}:generateContent?key={api_key}"
        headers = {"Content-Type": "application/json"}

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

    start = time.time()
    resp = requests.post(url, headers=headers, json=payload, timeout=180)
    resp.raise_for_status()
    elapsed = time.time() - start

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

    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]
        raise RuntimeError(f"이미지 파트 없음. 텍스트: {text_parts[:2]}")

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

    ext = ".jpg" if "jpeg" in mime else ".png"
    bg_path = BG_PATH.with_suffix(ext)
    bg_path.write_bytes(img_bytes)

    print(f"  배경 저장: {bg_path} ({len(img_bytes):,} bytes, {elapsed:.1f}초)")
    return bg_path


# ─────────────────────────────────────────────────────────────────────
# Step 2: HTML 오버레이 + Playwright 캡처
# ─────────────────────────────────────────────────────────────────────

def capture_overlay(bg_path: Path) -> None:
    print("[Step 2] HTML 오버레이 생성 및 Playwright 캡처...")

    bg_url = f"file://{bg_path.resolve()}"
    html_content = HTML_TEMPLATE.format(bg_url=bg_url)

    # 임시 HTML 파일 저장
    html_path = OUTPUT_DIR / "_tmp_sample_a_portrait.html"
    html_path.write_text(html_content, encoding="utf-8")
    print(f"  HTML 템플릿 저장: {html_path}")

    with sync_playwright() as p:
        browser = p.chromium.launch(
            args=[
                "--no-sandbox",
                "--disable-setuid-sandbox",
                "--font-render-hinting=none",
            ]
        )
        try:
            page = browser.new_page(viewport={"width": 1080, "height": 1080})

            # 로컬 폰트 로드를 위해 file:// 프로토콜 사용
            page.goto(f"file://{html_path.resolve()}", wait_until="networkidle")

            # 폰트 및 이미지 렌더링 완료 대기
            page.wait_for_timeout(2500)

            FINAL_PATH.parent.mkdir(parents=True, exist_ok=True)
            page.screenshot(path=str(FINAL_PATH), type="png", full_page=False)
            print(f"  캡처 완료: {FINAL_PATH}")
        finally:
            browser.close()

    # 임시 파일 정리
    html_path.unlink(missing_ok=True)

    size_kb = FINAL_PATH.stat().st_size / 1024
    print(f"  최종 이미지: {FINAL_PATH} ({size_kb:.0f} KB)")


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

def main():
    print("=" * 60)
    print("sample-A-portrait 하이브리드 이미지 생성")
    print(f"출력: {FINAL_PATH}")
    print("=" * 60)

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

    # Step 1: 배경 생성
    bg_path = generate_background()

    # Step 2: HTML 오버레이 + 캡처
    capture_overlay(bg_path)

    total = time.time() - total_start
    print(f"\n완료! 총 소요: {total:.1f}초")
    print(f"결과물: {FINAL_PATH}")


if __name__ == "__main__":
    main()
