#!/usr/bin/env python3
"""컨셉 21(코카콜라), 22(갤럭시), 23(나이키) 하이브리드 이미지 생성기.

1단계: Gemini API로 배경 이미지 생성
2단계: Playwright로 HTML/CSS 텍스트 오버레이 합성 → PNG 저장
"""

from __future__ import annotations

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

import requests
from playwright.sync_api import sync_playwright

sys.path.insert(0, str(Path(__file__).parent))
import gcloud_auth
from gen_config import CORE_METRIC_MIN_PX, CTA_MIN_PX, FONT_DIR, HEAD_SUB_RATIO, SUBHEAD_MIN_PX, WORKSPACE_ROOT

# ── 디자인 토큰 ──
_CTA_PX = CTA_MIN_PX
_SIZE_42PX = 42
_SIZE_44PX = 44
_SUBHEAD_PX = SUBHEAD_MIN_PX
_SIZE_88PX = 88
_METRIC_PX = CORE_METRIC_MIN_PX
_SIZE_112PX = 112
_LH_1_1 = 1.1
_LH_1_15 = 1.15
_LH_1_2 = 1.2
_LH_RATIO = HEAD_SUB_RATIO


# ─────────────────────────────────────────────────────────────────
# 상수
# ─────────────────────────────────────────────────────────────────

OUTPUT_BASE = WORKSPACE_ROOT / "output/meta-ads/concept-catalog"
GEMINI_API_BASE = "https://generativelanguage.googleapis.com/v1beta"
GEMINI_SCOPE = "https://www.googleapis.com/auth/generative-language"
MODEL_ID = "gemini-3.1-flash-image-preview"
FALLBACK_MODEL_ID = "gemini-3-pro-image-preview"

CONCEPTS = {
    "21": {
        "folder": "21-cocacola-style",
        "bg_prompt": (
            "Warm cream white background with soft red wave curves at the top, "
            "warm and inviting atmosphere, soft golden hour lighting feel, "
            "no text, no people, abstract warm shapes, "
            "cream white base #FFFDF9, red accent curves #F40009, golden yellow #FFCC00, "
            "1080x1080 square"
        ),
    },
    "22": {
        "folder": "22-galaxy-style",
        "bg_prompt": (
            "Deep space galaxy gradient background, dark navy #0A0E2E to purple #7B2FBE to electric blue, "
            "floating luminous particles and light streaks, premium tech aesthetic, "
            "cinematic quality, no text, abstract futuristic atmosphere, "
            "1080x1080 square"
        ),
    },
    "23": {
        "folder": "23-nike-style",
        "bg_prompt": (
            "Pure solid black background #0D0D0D, subtle very faint diagonal light streak "
            "from upper right corner, minimal, dramatic, no text, no objects, "
            "cinematic dark atmosphere, 1080x1080 square"
        ),
    },
}

# ─────────────────────────────────────────────────────────────────
# HTML 템플릿 생성 함수
# ─────────────────────────────────────────────────────────────────

def make_html_21(bg_path: str) -> str:
    """#21 코카콜라 스타일 HTML 오버레이"""
    return f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
  @import url('file://{FONT_DIR}/PretendardVariable.ttf');
  * {{ margin: 0; padding: 0; box-sizing: border-box; }}
  body {{ width: 1080px; height: 1080px; overflow: hidden; font-family: 'Pretendard', 'Noto Sans KR', sans-serif; }}
  .canvas {{
    width: 1080px; height: 1080px;
    background-image: url('file://{bg_path}');
    background-size: cover; background-position: center;
    position: relative;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
  }}
  .overlay {{
    position: absolute; inset: 0;
    background: rgba(255, 253, 249, 0.15);
  }}
  .content {{
    position: relative; z-index: 10;
    text-align: center;
    padding: 0 80px;
    display: flex; flex-direction: column;
    align-items: center; gap: 32px;
  }}
  .headline {{
    font-size: {_METRIC_PX}px;
    font-weight: 800;
    color: #1A0A00;
    line-height: {_LH_1_15};
    letter-spacing: -2px;
    text-shadow: 0 2px 8px rgba(255,253,249,0.8);
  }}
  .subtext {{
    font-size: {_SUBHEAD_PX}px;
    font-weight: 400;
    color: #1A0A00;
    line-height: {_LH_RATIO};
    text-shadow: 0 1px 4px rgba(255,253,249,0.8);
  }}
  .cta {{
    display: inline-block;
    background: #F40009;
    color: #FFFFFF;
    font-size: {_SIZE_44PX}px;
    font-weight: 700;
    padding: 22px 60px;
    border-radius: 60px;
    letter-spacing: 0;
    margin-top: 8px;
    box-shadow: 0 8px 32px rgba(244,0,9,0.4);
  }}
  .top-banner {{
    position: absolute; top: 0; left: 0; right: 0;
    height: 140px;
    background: #F40009;
    clip-path: ellipse(60% 100% at 50% 0%);
  }}
  .golden-dot {{
    position: absolute; bottom: 60px; left: 50%; transform: translateX(-50%);
    width: 80px; height: 8px; background: #FFCC00; border-radius: 4px;
  }}
</style>
</head>
<body>
<div class="canvas">
  <div class="overlay"></div>
  <div class="top-banner"></div>
  <div class="content">
    <div class="headline">열심히는 하는데,<br>월급은 제자리걸음?</div>
    <div class="subtext">당신의 이야기, 우리가 알고 있습니다</div>
    <div class="cta">지금 확인하기 →</div>
  </div>
  <div class="golden-dot"></div>
</div>
</body>
</html>"""


def make_html_22(bg_path: str) -> str:
    """#22 갤럭시 스타일 HTML 오버레이"""
    return f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
  * {{ margin: 0; padding: 0; box-sizing: border-box; }}
  body {{ width: 1080px; height: 1080px; overflow: hidden; font-family: 'Pretendard', 'Noto Sans KR', sans-serif; }}
  .canvas {{
    width: 1080px; height: 1080px;
    background-image: url('file://{bg_path}');
    background-size: cover; background-position: center;
    position: relative;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
  }}
  .overlay {{
    position: absolute; inset: 0;
    background: linear-gradient(180deg, rgba(10,14,46,0.2) 0%, rgba(10,14,46,0.6) 100%);
  }}
  .content {{
    position: relative; z-index: 10;
    text-align: center;
    padding: 0 80px;
    display: flex; flex-direction: column;
    align-items: center; gap: 36px;
  }}
  .headline {{
    font-size: {_SIZE_88PX}px;
    font-weight: 900;
    color: #FFFFFF;
    line-height: {_LH_1_2};
    letter-spacing: -2px;
    text-shadow: 0 0 60px rgba(91,191,255,0.5), 0 4px 16px rgba(0,0,0,0.6);
  }}
  .subtext {{
    font-size: {_SUBHEAD_PX}px;
    font-weight: 300;
    color: #5BBFFF;
    line-height: {_LH_RATIO};
    text-shadow: 0 0 30px rgba(91,191,255,0.6);
  }}
  .cta {{
    display: inline-block;
    background: rgba(91, 191, 255, 0.12);
    color: #FFFFFF;
    font-size: {_SIZE_42PX}px;
    font-weight: 500;
    padding: 20px 56px;
    border: 2px solid rgba(91, 191, 255, 0.7);
    border-radius: 60px;
    letter-spacing: 1px;
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    box-shadow: 0 0 32px rgba(91,191,255,0.25), inset 0 1px 0 rgba(255,255,255,0.2);
  }}
  .accent-line {{
    position: absolute; bottom: 80px; left: 50%; transform: translateX(-50%);
    width: 120px; height: 3px;
    background: linear-gradient(90deg, transparent, #5BBFFF, transparent);
  }}
</style>
</head>
<body>
<div class="canvas">
  <div class="overlay"></div>
  <div class="content">
    <div class="headline">열심히는 하는데,<br>월급은 제자리걸음?</div>
    <div class="subtext">기술이 당신의 커리어를 업그레이드합니다</div>
    <div class="cta">T.O.P 확인하기</div>
  </div>
  <div class="accent-line"></div>
</div>
</body>
</html>"""


def make_html_23(bg_path: str) -> str:
    """#23 나이키 스타일 HTML 오버레이"""
    return f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
  * {{ margin: 0; padding: 0; box-sizing: border-box; }}
  body {{ width: 1080px; height: 1080px; overflow: hidden; font-family: 'Pretendard', 'Noto Sans KR', sans-serif; }}
  .canvas {{
    width: 1080px; height: 1080px;
    background-image: url('file://{bg_path}');
    background-size: cover; background-position: center;
    position: relative;
  }}
  .overlay {{
    position: absolute; inset: 0;
    background: rgba(13, 13, 13, 0.25);
  }}
  .sub-pre {{
    position: absolute;
    top: 240px; left: 80px;
    font-size: {_SUBHEAD_PX}px;
    font-weight: 400;
    color: rgba(255,255,255,0.85);
    line-height: {_LH_1_2};
    letter-spacing: -1px;
  }}
  .headline {{
    position: absolute;
    top: 330px; left: 80px;
    font-size: {_SIZE_112PX}px;
    font-weight: 900;
    color: #FFFFFF;
    line-height: {_LH_1_1};
    letter-spacing: -4px;
    text-transform: none;
  }}
  .cta {{
    position: absolute;
    bottom: 100px; right: 80px;
    font-size: {_CTA_PX}px;
    font-weight: 700;
    color: #FF4500;
    letter-spacing: 0;
  }}
  .cta-underline {{
    position: absolute;
    bottom: 88px; right: 80px;
    width: 220px; height: 3px;
    background: #FF4500;
    opacity: 0.7;
  }}
</style>
</head>
<body>
<div class="canvas">
  <div class="overlay"></div>
  <div class="sub-pre">열심히는 하는데,</div>
  <div class="headline">월급은<br>제자리걸음?</div>
  <div class="cta">지금 바꿔 →</div>
  <div class="cta-underline"></div>
</div>
</body>
</html>"""


# ─────────────────────────────────────────────────────────────────
# Gemini 배경 생성
# ─────────────────────────────────────────────────────────────────

def generate_bg(token: str, prompt: str, output_path: Path, label: str) -> bool:
    """Gemini API로 배경 이미지를 생성하여 저장. 성공 여부 반환."""
    for model in [MODEL_ID, FALLBACK_MODEL_ID]:
        url = f"{GEMINI_API_BASE}/models/{model}:generateContent"
        headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
        payload = {
            "contents": [{"parts": [{"text": prompt}]}],
            "generationConfig": {"responseModalities": ["IMAGE", "TEXT"]},
        }
        print(f"  [{label}] Gemini 배경 생성 중... (모델: {model})")
        try:
            resp = requests.post(url, headers=headers, json=payload, timeout=300)
            if resp.status_code in (403, 404):
                print(f"  [{label}] {resp.status_code} — 다음 모델 시도")
                continue
            resp.raise_for_status()
            data = resp.json()
            parts = data.get("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"  [{label}] 이미지 파트 없음: {[p.get('text','')[:80] for p in parts]}")
                continue
            mime = img_part["inlineData"].get("mimeType", "image/jpeg")
            ext = ".jpg" if "jpeg" in mime else ".png"
            actual_path = output_path.with_suffix(ext)
            actual_path.write_bytes(base64.b64decode(img_part["inlineData"]["data"]))
            print(f"  [{label}] 배경 저장: {actual_path} ({actual_path.stat().st_size:,} bytes)")
            # 요청한 경로가 다르면 심볼릭 or 복사
            if actual_path != output_path:
                import shutil
                shutil.copy2(actual_path, output_path)
            return True
        except Exception as e:
            print(f"  [{label}] 오류: {e}")
    return False


# ─────────────────────────────────────────────────────────────────
# Playwright HTML → PNG
# ─────────────────────────────────────────────────────────────────

def capture_html(html_content: str, output_path: Path, label: str) -> None:
    """HTML 문자열을 임시 파일로 저장 후 Playwright로 캡처."""
    tmp_html = output_path.parent / "_overlay_tmp.html"
    tmp_html.write_text(html_content, encoding="utf-8")

    with sync_playwright() as p:
        browser = p.chromium.launch(args=["--disable-web-security", "--allow-file-access-from-files"])
        try:
            page = browser.new_page(viewport={"width": 1080, "height": 1080})
            page.goto(f"file://{tmp_html.resolve()}", wait_until="networkidle")
            # 폰트 로딩 대기
            page.wait_for_timeout(2000)
            output_path.parent.mkdir(parents=True, exist_ok=True)
            page.screenshot(path=str(output_path), type="png")
            print(f"  [{label}] PNG 저장: {output_path} ({output_path.stat().st_size:,} bytes)")
        finally:
            browser.close()

    tmp_html.unlink(missing_ok=True)


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

def main() -> None:
    print("=" * 60)
    print("컨셉 21/22/23 하이브리드 이미지 생성 시작")
    print("=" * 60)

    # 인증 토큰 획득
    print("\n[인증] Gemini SA 토큰 획득 중...")
    token = gcloud_auth.get_access_token()
    print(f"[인증] 토큰 획득 성공 (길이: {len(token)})")

    results = []

    for cid, cfg in CONCEPTS.items():
        folder = OUTPUT_BASE / cfg["folder"]
        folder.mkdir(parents=True, exist_ok=True)
        bg_path = folder / "bg.jpg"
        out_path = folder / "sample.png"
        label = f"#{cid}"

        print(f"\n{'─'*50}")
        print(f"[{label}] {cfg['folder']} 생성 시작")
        t0 = time.time()

        # 1단계: 배경 생성
        ok = generate_bg(token, cfg["bg_prompt"], bg_path, label)
        if not ok:
            print(f"  [{label}] 배경 생성 실패 — 건너뜀")
            results.append((cid, False, "bg failed"))
            continue

        # 실제 저장된 배경 파일 찾기 (확장자가 다를 수 있음)
        actual_bg = bg_path
        for ext in [".jpg", ".png", ".jpeg"]:
            candidate = bg_path.with_suffix(ext)
            if candidate.exists():
                actual_bg = candidate
                break

        # 2단계: HTML 오버레이 생성
        html_makers = {"21": make_html_21, "22": make_html_22, "23": make_html_23}
        html_content = html_makers[cid](str(actual_bg.resolve()))

        # 3단계: Playwright 캡처
        try:
            capture_html(html_content, out_path, label)
            elapsed = time.time() - t0
            print(f"  [{label}] 완료 ({elapsed:.1f}초)")
            results.append((cid, True, str(out_path)))
        except Exception as e:
            print(f"  [{label}] Playwright 오류: {e}")
            results.append((cid, False, str(e)))

    # 요약
    print(f"\n{'='*60}")
    print("생성 결과 요약")
    print(f"{'='*60}")
    for cid, ok, info in results:
        status = "OK" if ok else "FAIL"
        print(f"  [#{cid}] {status} | {info}")

    # 복사 (sample.png → concept-named.png)
    print("\n[복사] 컨셉명 파일 복사 중...")
    copy_map = {
        "21": ("21-cocacola-style/sample.png", "21-cocacola-style/21-cocacola-style.png"),
        "22": ("22-galaxy-style/sample.png", "22-galaxy-style/22-galaxy-style.png"),
        "23": ("23-nike-style/sample.png", "23-nike-style/23-nike-style.png"),
    }
    import shutil
    for cid, (src_rel, dst_rel) in copy_map.items():
        src = OUTPUT_BASE / src_rel
        dst = OUTPUT_BASE / dst_rel
        if src.exists():
            shutil.copy2(src, dst)
            print(f"  복사 완료: {dst}")
        else:
            print(f"  [경고] 원본 없음: {src}")

    print("\n모든 작업 완료.")


if __name__ == "__main__":
    main()
