#!/usr/bin/env python3
"""v2 Hybrid 광고 이미지 파이프라인 — Gemini 배경 + HTML 오버레이"""

import argparse
import base64
import json
import subprocess
import time
from datetime import datetime
from pathlib import Path
from typing import Any

import requests
from playwright.sync_api import sync_playwright

# ─────────────────────────────────────────────────────────────────────────────
# 상수 정의
# ─────────────────────────────────────────────────────────────────────────────

WORKSPACE = Path("/home/jay/workspace")
OUTPUT_BASE = WORKSPACE / "output/campaign-top/v2-hybrid"
TEMPLATE_DIR = WORKSPACE / "teams/dev1"
CAROUSEL_TEMPLATE = TEMPLATE_DIR / "v2_carousel_template.html"
GFA_TEMPLATE = TEMPLATE_DIR / "v2_gfa_template.html"

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_PROMPTS = {
    # A그룹 (서울대보험쌤) - 5 슬라이드
    "a1_hook": (
        "Premium modern office with floor-to-ceiling windows overlooking Seoul cityscape. "
        "Golden hour warm lighting, volumetric light rays through glass. "
        "Clean minimalist desk with premium accessories. Confident professional atmosphere. "
        "No text, no people, no watermark. Photorealistic. 1:1 square format."
    ),
    "a2_problem": (
        "Small cramped cluttered office cubicle. Dim fluorescent lighting, grey walls. "
        "Stacks of paper on old desk, outdated monitor. Feeling of isolation and frustration. "
        "Dark moody atmosphere, desaturated cool tones. "
        "No text, no people, no watermark. Photorealistic. 1:1 square."
    ),
    "a3_solution": (
        "Bright modern open-plan office with collaborative workspace. "
        "Natural daylight streaming in, white and light wood interiors. "
        "Multiple screens showing data dashboards. Team energy feeling. "
        "Clean, organized, tech-forward environment. "
        "No text, no people, no watermark. Photorealistic. 1:1 square."
    ),
    "a4_proof": (
        "Close-up of large premium monitor screen displaying upward growth chart and analytics dashboard. "
        "Green ascending line graph, data visualization. Soft blue ambient glow from screen. "
        "Premium desk setup with modern keyboard. Achievement and success feel. "
        "No text, no people, no watermark. Photorealistic. 1:1 square."
    ),
    "a5_cta": (
        "Bright sunrise view through modern office window. Golden warm light flooding in. "
        "Open door leading to bright light, symbolizing new beginning and opportunity. "
        "Clean modern hallway, premium corporate interior. Hope and optimism. "
        "No text, no people, no watermark. Photorealistic. 1:1 square."
    ),
    # B그룹 (인카금융) - 5 슬라이드
    "b1_hook": (
        "Impressive large-scale corporate headquarters building exterior at twilight. "
        "Modern glass skyscraper with blue accent lighting. Authoritative and established feel. "
        "Clean architectural lines, premium corporate presence. "
        "No text, no people, no watermark. Photorealistic. 1:1 square."
    ),
    "b2_problem": (
        "Empty corporate meeting room with unanswered questions feel. "
        "Scattered documents on conference table, empty chairs. "
        "Slightly foggy window, uncertain atmosphere. Cool blue-grey tones. "
        "No text, no people, no watermark. Photorealistic. 1:1 square."
    ),
    "b3_solution": (
        "Large professional boardroom with long conference table. "
        "Premium leather chairs, large display screens on wall showing organizational chart. "
        "Floor-to-ceiling windows, city view. Corporate power and structure. "
        "Blue accent lighting, modern corporate design. "
        "No text, no people, no watermark. Photorealistic. 1:1 square."
    ),
    "b4_proof": (
        "Abstract business growth visualization. Multiple upward arrows in 3D space. "
        "Blue and teal color scheme with gold accent highlights. "
        "Data visualization elements floating in dark space. "
        "Premium corporate data dashboard feel. "
        "No text, no people, no watermark. Photorealistic. 1:1 square."
    ),
    "b5_cta": (
        "Modern corporate office lobby with warm welcoming lighting. "
        "Clean marble floors, premium reception area. Glass walls showing bustling office beyond. "
        "Warm golden accent lights, inviting professional atmosphere. "
        "No text, no people, no watermark. Photorealistic. 1:1 square."
    ),
}

# ─────────────────────────────────────────────────────────────────────────────
# 슬라이드 데이터 (카피)
# ─────────────────────────────────────────────────────────────────────────────

SLIDE_DATA = {
    # A그룹 캐러셀
    "a1_hook": {
        "slideType": "hook",
        "brand": "A",
        "headline": "보험 영업,\n아직도 혼자 버티세요?",
        "subText": "서울대 출신 전문가가 설계한 시스템으로 바꿔보세요.",
    },
    "a2_problem": {
        "slideType": "problem",
        "brand": "A",
        "headline": "DB 없고, 멘토 없고,\n수입도 불안",
        "subText": "혼자 뛰는 보험 영업, 정착까지 버티는 사람이 드뭅니다.",
    },
    "a3_solution": {
        "slideType": "solution",
        "brand": "A",
        "headline": "서울대 출신이 만든\nAI 영업 시스템",
        "subText": "30종 DB·5대 AI 무기·1:1 코칭으로 빠르게 정착.",
    },
    "a4_proof": {
        "slideType": "proof",
        "brand": "A",
        "headline": "정착률 99%,\n숫자가 증명합니다",
        "subText": "24시간 세일즈캠퍼스, 서울대 기획 시스템으로 성장한 팀.",
    },
    "a5_cta": {
        "slideType": "cta",
        "brand": "A",
        "headline": "지금 딱 한 번만\n물어보세요",
        "subText": "경력·신입 모두 환영. 정착지원금 지원 가능.*",
        "ctaText": "무료 상담 신청",
        "disclaimer": "*조건 있음, 상담 시 확인",
    },
    # B그룹 캐러셀
    "b1_hook": {
        "slideType": "hook",
        "brand": "B",
        "headline": "대형 법인GA,\n시작이 다릅니다",
        "subText": "수수료 매출 1,863% 성장, 검증된 조직이 기다립니다.",
    },
    "b2_problem": {
        "slideType": "problem",
        "brand": "B",
        "headline": "좋은 회사인지,\n어떻게 알죠?",
        "subText": "규모·안정성·지원 체계, 세 가지를 동시에 갖춘 곳은 드뭅니다.",
    },
    "b3_solution": {
        "slideType": "solution",
        "brand": "B",
        "headline": "인카금융 TOP사업단의\n검증된 구조",
        "subText": "제휴 보험사 30개사, 본부 5개·지점 10개·구성원 200명+.",
    },
    "b4_proof": {
        "slideType": "proof",
        "brand": "B",
        "headline": "482명→5,500명,\n성장의 증명",
        "subText": "수수료 매출 120억→2,236억. 정착률 99%의 안정감.",
    },
    "b5_cta": {
        "slideType": "cta",
        "brand": "B",
        "headline": "안정적인 출발,\n지금 확인하세요",
        "subText": "경력·신입 정착지원금 별도 지원.* 함께 성장할 동료 모집.",
        "ctaText": "지금 상담받기",
        "disclaimer": "*조건 있음, 상담 시 확인",
    },
}

# GFA 배너 데이터
GFA_DATA = {
    "gfa_a": {
        "slideType": "gfa",
        "brand": "A",
        "headline": "서울대보험쌤 TOP사업단",
        "subText": "수수료 1,863% 성장, 정착률 99%",
        "ctaText": "무료 상담 신청",
        "disclaimer": "*조건 있음, 상담 시 확인",
    },
    "gfa_b": {
        "slideType": "gfa",
        "brand": "B",
        "headline": "인카금융 TOP사업단",
        "subText": "검증된 조직, 함께 성장하세요",
        "ctaText": "지금 상담받기",
        "disclaimer": "*조건 있음, 상담 시 확인",
    },
}

# ─────────────────────────────────────────────────────────────────────────────
# 인증
# ─────────────────────────────────────────────────────────────────────────────


def get_gcloud_token() -> str:
    """gcloud access token 획득"""
    result = subprocess.run(
        ["gcloud", "auth", "print-access-token", f"--scopes={GEMINI_SCOPE}"],
        capture_output=True,
        text=True,
        check=True,
    )
    token = result.stdout.strip()
    if not token:
        raise RuntimeError("gcloud auth print-access-token이 빈 토큰을 반환했습니다.")
    return token


# ─────────────────────────────────────────────────────────────────────────────
# 배경 이미지 생성
# ─────────────────────────────────────────────────────────────────────────────


def generate_background(token: str, prompt: str, output_path: Path, label: str) -> dict[str, Any]:
    """Gemini API로 배경 이미지 생성"""
    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"]},
    }

    print(f"  [{label}] 배경 생성 중...")
    start = time.time()
    response = requests.post(url, headers=headers, json=payload, timeout=300)
    response.raise_for_status()
    elapsed = time.time() - start

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

    parts = candidates[0].get("content", {}).get("parts", [])
    image_part = next((p for p in parts if "inlineData" in p), None)
    if not image_part:
        text_parts = [p.get("text", "") for p in parts if "text" in p]
        raise RuntimeError(f"이미지 데이터 없음. 텍스트 파트: {text_parts[:2]}")

    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.parent.mkdir(parents=True, exist_ok=True)
    final_path.write_bytes(image_bytes)

    size = final_path.stat().st_size
    print(f"  [{label}] 완료: {final_path.name} ({size:,} bytes, {elapsed:.1f}초)")
    return {"path": final_path, "size": size, "time": elapsed, "error": None}


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


def capture_hybrid(
    page,
    template_path: Path,
    data: dict,
    bg_path: Path,
    output_path: Path,
    label: str,
) -> dict:
    """HTML 템플릿 + 배경 -> Playwright 캡처"""
    if not template_path.exists():
        raise FileNotFoundError(f"템플릿 파일을 찾을 수 없습니다: {template_path}")
    if not bg_path.exists():
        raise FileNotFoundError(f"배경 이미지를 찾을 수 없습니다: {bg_path}")

    template_url = f"file://{template_path.resolve()}"
    page.goto(template_url, wait_until="networkidle")

    page.evaluate(f"""() => {{
        window.BG_IMAGE_PATH = "file://{bg_path.resolve()}";
        window.SCENARIO_DATA = {json.dumps(data, ensure_ascii=False)};
        if (typeof render === 'function') {{
            render(window.SCENARIO_DATA, window.BG_IMAGE_PATH);
        }}
    }}""")

    page.wait_for_timeout(2000)  # 폰트 + 배경 로딩 대기

    output_path.parent.mkdir(parents=True, exist_ok=True)
    page.screenshot(path=str(output_path), type="png")
    size = output_path.stat().st_size
    print(f"  [{label}] 캡처 완료: {output_path.name} ({size:,} bytes)")
    return {"path": output_path, "size": size, "error": None}


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


def main():
    parser = argparse.ArgumentParser(description="v2 Hybrid 광고 이미지 파이프라인")
    parser.add_argument(
        "--skip-bg",
        action="store_true",
        help="배경 생성 스킵 (기존 배경 사용)",
    )
    parser.add_argument(
        "--group",
        choices=["a", "b", "all"],
        default="all",
        help="생성할 그룹",
    )
    args = parser.parse_args()

    # 출력 디렉토리
    dir_a = OUTPUT_BASE / "meta-carousel-a"
    dir_b = OUTPUT_BASE / "meta-carousel-b"
    dir_gfa = OUTPUT_BASE / "naver-gfa"
    bg_dir = OUTPUT_BASE / "backgrounds"

    for d in [dir_a, dir_b, dir_gfa, bg_dir]:
        d.mkdir(parents=True, exist_ok=True)

    results: dict[str, list] = {
        "backgrounds": [],
        "carousels": [],
        "gfa": [],
        "errors": [],
    }

    # ─────────────────────────────────────────────────────────────────────────
    # Phase 1: 배경 이미지 생성
    # ─────────────────────────────────────────────────────────────────────────
    if not args.skip_bg:
        print("=" * 60)
        print("Phase 1: Gemini 배경 이미지 생성")
        print("=" * 60)

        try:
            token = get_gcloud_token()
            print(f"[인증] 토큰 획득 성공 (길이: {len(token)} chars)")
        except Exception as e:
            error = f"토큰 획득 실패: {type(e).__name__}: {e}"
            print(f"  [ERROR] {error}")
            results["errors"].append(error)
            token = None

        if token:
            # 그룹 필터링
            prompts_to_gen: dict[str, str] = {}
            if args.group in ("a", "all"):
                prompts_to_gen.update({k: v for k, v in BG_PROMPTS.items() if k.startswith("a")})
            if args.group in ("b", "all"):
                prompts_to_gen.update({k: v for k, v in BG_PROMPTS.items() if k.startswith("b")})

            for key, prompt in prompts_to_gen.items():
                bg_path = bg_dir / f"bg_{key}.jpg"
                try:
                    result = generate_background(token, prompt, bg_path, key)
                    results["backgrounds"].append({"key": key, **result, "path": str(result["path"])})
                except requests.HTTPError as e:
                    error = f"배경 생성 실패 [{key}] HTTP {e.response.status_code}: " f"{e.response.text[:300]}"
                    print(f"  [ERROR] {error}")
                    results["errors"].append(error)
                except Exception as e:
                    error = f"배경 생성 실패 [{key}]: {type(e).__name__}: {e}"
                    print(f"  [ERROR] {error}")
                    results["errors"].append(error)
                time.sleep(2)  # API rate limit 방지
    else:
        print("[Phase 1] --skip-bg 옵션으로 배경 생성 스킵")

    # ─────────────────────────────────────────────────────────────────────────
    # Phase 2: 캐러셀 캡처 (1080x1080)
    # ─────────────────────────────────────────────────────────────────────────
    print("\n" + "=" * 60)
    print("Phase 2: Playwright 캡처 (캐러셀)")
    print("=" * 60)

    with sync_playwright() as p:
        browser = p.chromium.launch()

        carousel_page = browser.new_page(viewport={"width": 1080, "height": 1080})

        slides_to_gen: dict[str, dict] = {}
        if args.group in ("a", "all"):
            slides_to_gen.update({k: v for k, v in SLIDE_DATA.items() if k.startswith("a")})
        if args.group in ("b", "all"):
            slides_to_gen.update({k: v for k, v in SLIDE_DATA.items() if k.startswith("b")})

        for key, data in slides_to_gen.items():
            # 배경 이미지 탐색: .jpg 우선, 없으면 .png
            bg_path = bg_dir / f"bg_{key}.jpg"
            if not bg_path.exists():
                bg_path = bg_dir / f"bg_{key}.png"
            if not bg_path.exists():
                error = f"배경 이미지 없음: {key}"
                print(f"  [ERROR] {error}")
                results["errors"].append(error)
                continue

            # 출력 경로 결정
            slide_num = key[1]  # "a1_hook" -> "1"
            if key.startswith("a"):
                out_path = dir_a / f"slide_{slide_num}.png"
            else:
                out_path = dir_b / f"slide_{slide_num}.png"

            try:
                result = capture_hybrid(carousel_page, CAROUSEL_TEMPLATE, data, bg_path, out_path, key)
                results["carousels"].append({"key": key, "path": str(out_path), "size": result["size"]})
            except Exception as e:
                error = f"캡처 실패 [{key}]: {type(e).__name__}: {e}"
                print(f"  [ERROR] {error}")
                results["errors"].append(error)

        # ─────────────────────────────────────────────────────────────────────
        # Phase 3: GFA 배너 캡처 (1200x628)
        # ─────────────────────────────────────────────────────────────────────
        print("\n" + "=" * 60)
        print("Phase 3: GFA 배너 캡처")
        print("=" * 60)

        gfa_page = browser.new_page(viewport={"width": 1200, "height": 628})

        for key, data in GFA_DATA.items():
            # GFA는 각 그룹의 slide 1 배경 재사용
            if key == "gfa_a":
                bg_key = "a1_hook"
            else:
                bg_key = "b1_hook"

            bg_path = bg_dir / f"bg_{bg_key}.jpg"
            if not bg_path.exists():
                bg_path = bg_dir / f"bg_{bg_key}.png"
            if not bg_path.exists():
                error = f"GFA 배경 이미지 없음: {bg_key}"
                print(f"  [ERROR] {error}")
                results["errors"].append(error)
                continue

            out_name = "gfa_a.png" if key == "gfa_a" else "gfa_b.png"
            out_path = dir_gfa / out_name

            try:
                result = capture_hybrid(gfa_page, GFA_TEMPLATE, data, bg_path, out_path, key)
                results["gfa"].append({"key": key, "path": str(out_path), "size": result["size"]})
            except Exception as e:
                error = f"GFA 캡처 실패 [{key}]: {type(e).__name__}: {e}"
                print(f"  [ERROR] {error}")
                results["errors"].append(error)

        browser.close()

    # ─────────────────────────────────────────────────────────────────────────
    # 결과 요약 및 저장
    # ─────────────────────────────────────────────────────────────────────────
    print("\n" + "=" * 60)
    print("결과 요약")
    print("=" * 60)
    print(f"배경: {len(results['backgrounds'])}장")
    print(f"캐러셀: {len(results['carousels'])}장")
    print(f"GFA: {len(results['gfa'])}장")
    print(f"에러: {len(results['errors'])}건")

    if results["errors"]:
        print("\n[에러 목록]")
        for err in results["errors"]:
            print(f"  - {err}")

    # 결과 JSON 저장
    results_path = OUTPUT_BASE / "results.json"
    with open(results_path, "w", encoding="utf-8") as f:
        json.dump(results, f, ensure_ascii=False, indent=2, default=str)
    print(f"\n결과 저장: {results_path}")


if __name__ == "__main__":
    main()
