#!/usr/bin/env python3
"""Cell-1 인카금융서비스 '정당한 보상' 배너 생성기 (v3.2 최종본).

Gemini API로 포토리얼 배경을 생성하고,
HTML/CSS + Playwright로 한글 텍스트를 정밀하게 오버레이합니다.

출력:
  - /home/jay/workspace/output/banners/cell-1-incar-fair/meta-feed-1080x1080.png
  - /home/jay/workspace/output/banners/cell-1-incar-fair/google-resp-1200x628.png
"""

from __future__ import annotations

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

import requests
from playwright.sync_api import sync_playwright

# ─── 경로 설정 ────────────────────────────────────────────────────────────────

TOOL_DIR = Path(__file__).parent
sys.path.insert(0, str(TOOL_DIR))

import gcloud_auth  # noqa: E402

OUTPUT_DIR = Path("/home/jay/workspace/output/banners/cell-1-incar-fair")
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

TMP_DIR = TOOL_DIR / "output" / "v4-hybrid" / "cell-1-incar-fair"
TMP_DIR.mkdir(parents=True, exist_ok=True)

# 폴백 배경 이미지
FALLBACK_BG = Path("/home/jay/workspace/output/meta-ads/concept-catalog/35-hybrid-v4-refined-A/bg.png")

# ─── Gemini API 설정 ──────────────────────────────────────────────────────────

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

# API 키 (환경변수 또는 직접 지정)
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "AIzaSyDEy7IcOoTbQsI4nxfPOw3ZFbYqEL_PgFU")

# ─── 배경 프롬프트 ────────────────────────────────────────────────────────────

BG_PROMPT_1080 = (
    "Professional financial advisor's mahogany desk with scattered contract documents "
    "and a fountain pen, dramatic side lighting through venetian blinds casting shadow "
    "patterns, deep navy blue and warm amber tones, cinematic shallow depth of field, "
    "photorealistic office scene, no people, no text, no logos. Square 1:1 format."
)

BG_PROMPT_1200 = (
    "Wide panoramic view of a modern Korean corporate office at golden hour, glass windows "
    "with warm sunlight streaming in, premium mahogany desk with financial documents, "
    "warm amber and navy tones, cinematic composition, photorealistic, no people, no text, "
    "no logos. Wide landscape 1.91:1 format."
)

# ─── HTML 템플릿: 1080x1080 (Template B - 전체 배경 + 다크 오버레이 + 중앙 반투명 패널) ───

HTML_1080x1080 = """<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=1080">
  <style>
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Black.otf') format('opentype'); font-weight: 900; }}
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-ExtraBold.otf') format('opentype'); font-weight: 800; }}
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Bold.otf') format('opentype'); font-weight: 700; }}
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-SemiBold.otf') format('opentype'); font-weight: 600; }}
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Medium.otf') format('opentype'); font-weight: 500; }}
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Regular.otf') format('opentype'); font-weight: 400; }}

    *, *::before, *::after {{ box-sizing: border-box; margin: 0; padding: 0; }}
    html, body {{ width: 1080px; height: 1080px; overflow: hidden; font-family: 'Pretendard', sans-serif; word-break: keep-all; }}

    .canvas {{ position: relative; width: 1080px; height: 1080px; overflow: hidden; }}
    .bg-image {{ position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; }}
    .dark-overlay {{ position: absolute; inset: 0; background: rgba(10, 22, 40, 0.58); }}

    /* 중앙 크림 반투명 패널 */
    .text-panel {{
      position: absolute;
      top: 50%; left: 50%;
      transform: translate(-50%, -50%);
      width: 860px;
      padding: 56px 48px;
      background: rgba(255, 248, 231, 0.82);
      border-radius: 12px;
      backdrop-filter: blur(4px);
      box-shadow: 0 8px 32px rgba(0,0,0,0.2);
      display: flex; flex-direction: column;
      align-items: center;
      gap: 28px; text-align: center;
    }}

    .badge {{
      display: inline-block;
      background: #C9A84C; color: #1A0E00;
      font-size: 40px; font-weight: 700;
      height: 52px; padding: 0 24px;
      border-radius: 6px;
      white-space: nowrap;
      letter-spacing: -0.03em;
      line-height: 52px;
    }}

    .headline {{
      font-size: 60px; font-weight: 700;
      color: #3E2723; line-height: 1.25;
      letter-spacing: -1.5px;
    }}
    .headline .gold {{ color: #C9A84C; }}

    .sub-copy {{
      font-size: 44px; font-weight: 500;
      color: #A07828;
      white-space: nowrap;
      letter-spacing: -0.02em;
    }}

    .cta-btn {{
      display: inline-block;
      background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
      color: #1A0E00;
      font-size: 48px; font-weight: 700;
      height: 76px; line-height: 76px;
      padding: 0 40px;
      min-width: 360px;
      width: auto;
      border-radius: 6px;
      box-shadow: 0 6px 24px rgba(201,168,76,0.45);
      white-space: nowrap;
      letter-spacing: -0.03em;
      text-align: center;
    }}
  </style>
</head>
<body>
  <div class="canvas">
    <img class="bg-image" src="{bg_url}" alt="background">
    <div class="dark-overlay"></div>
    <div class="text-panel">
      <span class="badge">인카금융서비스 TOP사업단</span>
      <p class="headline">같은 계약,<br>수수료가 왜 <span class="gold">다른가요?</span></p>
      <p class="sub-copy">정착지원금 최대 1,000만원<br>경력직 직전연봉 50% 지원</p>
      <div class="cta-btn">수익 구조 지금 확인 →</div>
    </div>
  </div>
</body>
</html>"""

# ─── HTML 템플릿: 1200x628 (Template A - 좌측 60% 텍스트 + 우측 40% 배경 노출) ───

HTML_1200x628 = """<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=1200">
  <style>
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Black.otf') format('opentype'); font-weight: 900; }}
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-ExtraBold.otf') format('opentype'); font-weight: 800; }}
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Bold.otf') format('opentype'); font-weight: 700; }}
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-SemiBold.otf') format('opentype'); font-weight: 600; }}
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Medium.otf') format('opentype'); font-weight: 500; }}
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Regular.otf') format('opentype'); font-weight: 400; }}

    *, *::before, *::after {{ box-sizing: border-box; margin: 0; padding: 0; }}
    html, body {{ width: 1200px; height: 628px; overflow: hidden; font-family: 'Pretendard', sans-serif; word-break: keep-all; }}

    .canvas {{ position: relative; width: 1200px; height: 628px; overflow: hidden; }}
    .bg-image {{ position: absolute; right: 0; top: 0; width: 65%; height: 100%; object-fit: cover; object-position: center right; }}

    .gradient-overlay {{
      position: absolute; inset: 0;
      background: linear-gradient(
        to right,
        rgba(10,22,40,0.95) 0%,
        rgba(10,22,40,0.95) 40%,
        rgba(10,22,40,0.85) 52%,
        rgba(10,22,40,0.50) 68%,
        rgba(10,22,40,0.15) 82%,
        transparent 100%
      );
    }}

    /* 좌측 골드 세로 액센트바 */
    .accent-bar {{
      position: absolute;
      top: 80px; left: 0;
      width: 4px; height: 460px;
      background: linear-gradient(to bottom, #C9A84C, #D4B87A);
      border-radius: 2px;
    }}

    .text-area {{
      position: absolute;
      top: 0; left: 0;
      width: 62%; height: 100%;
      padding: 48px 56px 48px 60px;
      display: flex; flex-direction: column;
      justify-content: center;
      gap: 20px;
    }}

    .badge {{
      display: inline-block;
      background: #C9A84C; color: #1A0E00;
      font-size: 40px; font-weight: 700;
      height: 48px; line-height: 48px;
      padding: 0 20px;
      border-radius: 6px;
      white-space: nowrap;
      letter-spacing: -0.03em;
      align-self: flex-start;
      margin-bottom: 6px;
    }}

    .headline {{
      font-size: 54px; font-weight: 700;
      color: #FFF8E7; line-height: 1.2;
      letter-spacing: -1.2px;
    }}
    .headline .gold {{ color: #C9A84C; }}

    .sub-copy {{
      font-size: 44px; font-weight: 500;
      color: #C9A84C;
      text-shadow: 0 1px 3px rgba(0,0,0,0.5);
      white-space: nowrap;
      letter-spacing: -0.02em;
    }}

    .cta-btn {{
      display: inline-block;
      background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
      color: #1A0E00;
      font-size: 44px; font-weight: 700;
      height: 56px; line-height: 56px;
      padding: 0 32px;
      min-width: 220px;
      width: auto;
      border-radius: 6px;
      box-shadow: 0 4px 16px rgba(201,168,76,0.35);
      white-space: nowrap;
      letter-spacing: -0.03em;
      align-self: flex-start;
      text-align: center;
      margin-top: 16px;
    }}
  </style>
</head>
<body>
  <div class="canvas">
    <img class="bg-image" src="{bg_url}" alt="background">
    <div class="gradient-overlay"></div>
    <div class="accent-bar"></div>
    <div class="text-area">
      <span class="badge">인카금융서비스 TOP사업단</span>
      <p class="headline">같은 계약,<br>수수료가 왜 <span class="gold">다른가요?</span></p>
      <p class="sub-copy">정착지원금 최대 1,000만원<br>경력직 직전연봉 50% 지원</p>
      <div class="cta-btn">수익 구조 지금 확인 →</div>
    </div>
  </div>
</body>
</html>"""


# ─── Gemini 이미지 생성 (API 키 방식) ─────────────────────────────────────────

def generate_bg_image_apikey(prompt: str, output_path: Path, label: str = "") -> Path | None:
    """Gemini API 키로 배경 이미지를 생성합니다."""
    print(f"[배경{label}] Gemini API 키 방식으로 이미지 생성 중...")
    start = time.time()

    # API 키 방식 엔드포인트
    url = f"{GEMINI_API_BASE}/models/{MODEL_ID}:generateContent?key={GEMINI_API_KEY}"
    headers = {"Content-Type": "application/json"}
    payload = {
        "contents": [{"parts": [{"text": prompt}]}],
        "generationConfig": {"responseModalities": ["IMAGE", "TEXT"]},
    }

    try:
        response = requests.post(url, headers=headers, json=payload, timeout=300)

        # fallback 모델 시도
        if response.status_code in (400, 403, 404):
            print(f"[배경{label}] 모델 {MODEL_ID} 실패 (HTTP {response.status_code}). Fallback: {FALLBACK_MODEL_ID}")
            url2 = f"{GEMINI_API_BASE}/models/{FALLBACK_MODEL_ID}:generateContent?key={GEMINI_API_KEY}"
            response = requests.post(url2, headers=headers, json=payload, timeout=300)

        if not response.ok:
            print(f"[배경{label}] API 오류: {response.status_code} - {response.text[:400]}")
            return None

        data = response.json()
        candidates = data.get("candidates", [])
        if not candidates:
            print(f"[배경{label}] 응답에 candidates 없음: {json.dumps(data)[:300]}")
            return None

        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"[배경{label}] 이미지 데이터 없음. 텍스트: {text_parts[:2]}")
            return None

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

        ext = ".jpg" if "jpeg" in mime_type else ".png"
        final_path = output_path.with_suffix(ext)
        final_path.write_bytes(image_bytes)

        elapsed = time.time() - start
        print(f"[배경{label}] 완료: {final_path.name} ({len(image_bytes):,} bytes, {elapsed:.1f}초)")
        return final_path

    except Exception as e:
        print(f"[배경{label}] 예외 발생: {e}")
        return None


def generate_bg_image_bearer(prompt: str, output_path: Path, token: str, label: str = "") -> Path | None:
    """Bearer 토큰으로 Gemini API 배경 이미지를 생성합니다."""
    print(f"[배경{label}] Bearer 토큰 방식으로 이미지 생성 중...")
    start = time.time()

    url = f"{GEMINI_API_BASE}/models/{MODEL_ID}:generateContent"
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }
    payload = {
        "contents": [{"parts": [{"text": prompt}]}],
        "generationConfig": {"responseModalities": ["IMAGE", "TEXT"]},
    }

    try:
        response = requests.post(url, headers=headers, json=payload, timeout=300)

        if response.status_code in (400, 403, 404):
            print(f"[배경{label}] 모델 {MODEL_ID} 실패 (HTTP {response.status_code}). Fallback: {FALLBACK_MODEL_ID}")
            url2 = f"{GEMINI_API_BASE}/models/{FALLBACK_MODEL_ID}:generateContent"
            response = requests.post(url2, headers=headers, json=payload, timeout=300)

        if not response.ok:
            print(f"[배경{label}] API 오류: {response.status_code} - {response.text[:400]}")
            return None

        data = response.json()
        candidates = data.get("candidates", [])
        if not candidates:
            print(f"[배경{label}] 응답에 candidates 없음: {json.dumps(data)[:300]}")
            return None

        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"[배경{label}] 이미지 데이터 없음. 텍스트: {text_parts[:2]}")
            return None

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

        ext = ".jpg" if "jpeg" in mime_type else ".png"
        final_path = output_path.with_suffix(ext)
        final_path.write_bytes(image_bytes)

        elapsed = time.time() - start
        print(f"[배경{label}] 완료: {final_path.name} ({len(image_bytes):,} bytes, {elapsed:.1f}초)")
        return final_path

    except Exception as e:
        print(f"[배경{label}] 예외 발생: {e}")
        return None


def get_or_generate_bg(prompt: str, output_path: Path, label: str = "") -> Path:
    """배경 이미지를 생성하거나 폴백을 사용합니다."""
    # 1. API 키 방식 시도
    result = generate_bg_image_apikey(prompt, output_path, label)
    if result:
        return result

    # 2. Bearer 토큰 방식 시도
    print(f"[배경{label}] API 키 방식 실패 → Bearer 토큰 방식 시도...")
    try:
        token = gcloud_auth.get_access_token()
        result = generate_bg_image_bearer(prompt, output_path, token, label)
        if result:
            return result
    except Exception as e:
        print(f"[배경{label}] Bearer 토큰 획득 실패: {e}")

    # 3. 폴백 이미지 사용
    print(f"[배경{label}] Gemini 생성 실패 → 폴백 이미지 사용: {FALLBACK_BG}")
    if FALLBACK_BG.exists():
        ext = FALLBACK_BG.suffix
        fallback_dest = output_path.with_suffix(ext)
        shutil.copy2(FALLBACK_BG, fallback_dest)
        print(f"[배경{label}] 폴백 복사 완료: {fallback_dest.name}")
        return fallback_dest
    else:
        raise RuntimeError(f"폴백 이미지도 없음: {FALLBACK_BG}")


# ─── Playwright HTML → PNG 캡처 ───────────────────────────────────────────────

def capture_html_to_png(
    html_content: str,
    bg_path: Path,
    html_output_path: Path,
    png_output_path: Path,
    width: int,
    height: int,
) -> None:
    """HTML 템플릿에 배경 이미지 URL을 삽입하고 Playwright로 PNG 캡처합니다."""
    bg_url = f"file://{bg_path.resolve()}"
    html_filled = html_content.format(bg_url=bg_url)

    # HTML 파일 저장 (산출물)
    html_output_path.write_text(html_filled, encoding="utf-8")
    print(f"[HTML] 저장 완료: {html_output_path}")

    # 임시 HTML도 동일 파일 사용
    print(f"[캡처] Playwright로 {width}x{height} 캡처 중...")
    with sync_playwright() as p:
        browser = p.chromium.launch(args=["--no-sandbox", "--disable-gpu"])
        try:
            page = browser.new_page(viewport={"width": width, "height": height})
            page.goto(f"file://{html_output_path.resolve()}", wait_until="networkidle")
            # 폰트 로딩 대기
            page.wait_for_timeout(2500)
            png_output_path.parent.mkdir(parents=True, exist_ok=True)
            page.screenshot(path=str(png_output_path), type="png", clip={
                "x": 0, "y": 0, "width": width, "height": height
            })
            print(f"[캡처] 저장 완료: {png_output_path}")
        finally:
            browser.close()


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

def main() -> None:
    print("=" * 60)
    print("Cell-1 인카금융서비스 '정당한 보상' 배너 생성 시작 (v3.2)")
    print("=" * 60)

    results = []

    # ── 배너 1: 1080x1080 (meta-feed) ─────────────────────────────────────────
    print("\n[Step 1] 1080x1080 배경 이미지 생성 중...")
    bg1080_path = TMP_DIR / "bg-cell1-1080"
    existing_1080 = list(TMP_DIR.glob("bg-cell1-1080.*"))
    if existing_1080:
        bg1080 = existing_1080[0]
        print(f"[배경1] 기존 이미지 재사용: {bg1080.name}")
    else:
        bg1080 = get_or_generate_bg(BG_PROMPT_1080, bg1080_path, "1080")

    # bg-cell1-1080.png를 출력 디렉토리에도 복사 (HTML에서 참조)
    bg1080_out = OUTPUT_DIR / ("bg-cell1-1080" + bg1080.suffix)
    if not bg1080_out.exists() or bg1080_out.stat().st_mtime < bg1080.stat().st_mtime:
        shutil.copy2(bg1080, bg1080_out)

    print("\n[Step 2] 1080x1080 배너 렌더링 중...")
    html_1080_path = OUTPUT_DIR / "meta-feed-1080x1080.html"
    png_1080_path = OUTPUT_DIR / "meta-feed-1080x1080.png"
    try:
        capture_html_to_png(
            html_content=HTML_1080x1080,
            bg_path=bg1080_out,
            html_output_path=html_1080_path,
            png_output_path=png_1080_path,
            width=1080,
            height=1080,
        )
        size_kb = png_1080_path.stat().st_size / 1024
        print(f"[배너1] 완료: {png_1080_path} ({size_kb:.0f} KB)")
        results.append(("meta-feed-1080x1080.png", "SUCCESS", f"{size_kb:.0f} KB"))
    except Exception as e:
        print(f"[배너1] 실패: {e}")
        import traceback; traceback.print_exc()
        results.append(("meta-feed-1080x1080.png", "FAILED", str(e)))

    # ── 배너 2: 1200x628 (google-resp) ────────────────────────────────────────
    print("\n[Step 3] 1200x628 배경 이미지 생성 중...")
    bg1200_path = TMP_DIR / "bg-cell1-1200"
    existing_1200 = list(TMP_DIR.glob("bg-cell1-1200.*"))
    if existing_1200:
        bg1200 = existing_1200[0]
        print(f"[배경2] 기존 이미지 재사용: {bg1200.name}")
    else:
        bg1200 = get_or_generate_bg(BG_PROMPT_1200, bg1200_path, "1200")

    bg1200_out = OUTPUT_DIR / ("bg-cell1-1200" + bg1200.suffix)
    if not bg1200_out.exists() or bg1200_out.stat().st_mtime < bg1200.stat().st_mtime:
        shutil.copy2(bg1200, bg1200_out)

    print("\n[Step 4] 1200x628 배너 렌더링 중...")
    html_1200_path = OUTPUT_DIR / "google-resp-1200x628.html"
    png_1200_path = OUTPUT_DIR / "google-resp-1200x628.png"
    try:
        capture_html_to_png(
            html_content=HTML_1200x628,
            bg_path=bg1200_out,
            html_output_path=html_1200_path,
            png_output_path=png_1200_path,
            width=1200,
            height=628,
        )
        size_kb = png_1200_path.stat().st_size / 1024
        print(f"[배너2] 완료: {png_1200_path} ({size_kb:.0f} KB)")
        results.append(("google-resp-1200x628.png", "SUCCESS", f"{size_kb:.0f} KB"))
    except Exception as e:
        print(f"[배너2] 실패: {e}")
        import traceback; traceback.print_exc()
        results.append(("google-resp-1200x628.png", "FAILED", str(e)))

    # ── 결과 요약 ──────────────────────────────────────────────────────────────
    print("\n" + "=" * 60)
    print("결과 요약")
    print("=" * 60)
    for fname, status, info in results:
        print(f"  [{status}] {fname} — {info}")

    print("\n산출물 경로:")
    for f in sorted(OUTPUT_DIR.iterdir()):
        size = f.stat().st_size / 1024
        print(f"  {f}  ({size:.0f} KB)")

    all_ok = all(s == "SUCCESS" for _, s, _ in results)
    if not all_ok:
        sys.exit(1)


if __name__ == "__main__":
    main()
