"""Concept #44 "Hangul Monument" — One Show 2024 Gold Pencil ADLaM-inspired ad.

Pure typographic advertisement: dark background + monumental Korean letterforms.
Output: 1080x1080px PNG saved to concept-catalog/44-oneshow-hangul-monument/
"""

from __future__ import annotations

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

import requests
from gen_config import WORKSPACE_ROOT

# Reuse project auth module
sys.path.insert(0, str(Path(__file__).parent))
import gcloud_auth  # noqa: E402

OUTPUT_DIR = WORKSPACE_ROOT / "output/meta-ads/concept-catalog/44-oneshow-hangul-monument"
SAMPLE_PATH = OUTPUT_DIR / "sample.png"
COPY_PATH   = OUTPUT_DIR / "44-hangul-monument.png"

MODEL_PRIMARY  = "gemini-3-pro-image-preview"
MODEL_FALLBACK = "gemini-3.1-flash-image-preview"
GEMINI_API_BASE = "https://generativelanguage.googleapis.com/v1beta"

PROMPT = """\
Create a 1:1 square format (1080x1080px) premium typographic advertisement poster.

BACKGROUND:
Solid dark charcoal color, almost black — hex #1A1A1A. Perfectly flat, no gradients, \
no texture. Pure dark void.

MAIN TYPOGRAPHY — THE HERO:
Three large Korean characters: 설 계 사
Each character is a monumental graphic object — rendered in massive, bold weight, \
approximately 55-60% of the canvas height. The three characters span 80% of the \
canvas width horizontally, with generous equal spacing between them.
Font style: heavy-weight Korean serif or ultra-bold sans-serif, extremely crisp and precise.
Color: warm cream-gold, approximately #E8D5B5 — like aged ivory or brushed brass.
Letter-spacing: wide, generous — treating each glyph as a sculpture.
The characters are vertically and horizontally centered on the canvas.
Treatment: Each Hangul character has the monumental presence of carved stone or \
cast gold — think ADLaM script in the Microsoft One Show 2024 campaign, \
where unfamiliar letterforms became precious art objects through sheer precision.

SECONDARY TEXT:
Below the main characters, centered, smaller:
Korean text: 당신의 다음 챕터
Style: light weight, approximately 1/3 the size of main characters.
Color: warm cream at 60% opacity — semi-transparent.

BOTTOM TEXT:
Near the bottom center:
Korean text: T.O.P 사업단 | 지금 상담 신청하기
Style: thin/light weight, small — approximately 1/5 the size of main characters.
Color: white at 50% opacity — semi-transparent.

LAYOUT RULES:
- Symmetrical vertical whitespace above and below the main character block
- All text elements are horizontally centered
- No decorative elements, no borders, no icons, no photos
- Pure typography — letterforms are the entire visual

STYLE REFERENCE:
- Microsoft ADLaM campaign (One Show 2024, 7x Gold Pencil) — script as prestige
- Luxury brand typographic posters (Céline, The Row, Bottega Veneta editorial)
- Characters treated like Hangul calligraphy elevated to monumental sculpture
- Maximum negative space, maximum typographic impact
- The aesthetic of museum-quality typography exhibitions

MOOD: Monumental. Prestigious. Silent power. The letterforms speak volumes through \
their sheer physical beauty and scale.

OUTPUT: Square 1:1 format PNG, 1080x1080px equivalent. No watermark.\
"""


def call_gemini(token: str, model: str) -> requests.Response:
    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"],
            "temperature": 1.0,
        },
    }
    return requests.post(url, headers=headers, json=payload, timeout=300)


def extract_image_bytes(response: requests.Response) -> tuple[bytes, str]:
    data = response.json()
    candidates = data.get("candidates", [])
    if not candidates:
        raise RuntimeError(f"No candidates in response: {str(data)[:300]}")
    parts = candidates[0].get("content", {}).get("parts", [])
    for part in parts:
        if "inlineData" in part:
            mime = part["inlineData"].get("mimeType", "image/jpeg")
            img_bytes = base64.b64decode(part["inlineData"]["data"])
            return img_bytes, mime
    text_parts = [p.get("text", "") for p in parts if "text" in p]
    raise RuntimeError(f"No image in response. Text parts: {text_parts[:2]}")


def main() -> None:
    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

    print("=" * 60)
    print("Concept #44 — Hangul Monument image generation")
    print("=" * 60)

    # Obtain token
    print("Obtaining auth token...")
    token = gcloud_auth.get_access_token()
    print(f"Token obtained (length: {len(token)} chars)")

    # Try primary model, fallback if needed
    for model in (MODEL_PRIMARY, MODEL_FALLBACK):
        print(f"\nCalling Gemini API — model: {model}")
        t0 = time.time()
        resp = call_gemini(token, model)
        elapsed = time.time() - t0
        print(f"  HTTP {resp.status_code} ({elapsed:.1f}s)")

        if resp.status_code in (403, 404):
            print(f"  Access denied ({resp.status_code}) — trying fallback model...")
            continue

        resp.raise_for_status()

        # Extract image
        img_bytes, mime = extract_image_bytes(resp)
        print(f"  Image received: {len(img_bytes):,} bytes, mime={mime}")

        # Determine extension
        ext = ".jpg" if "jpeg" in mime else ".png"
        sample = SAMPLE_PATH.with_suffix(ext)
        sample.write_bytes(img_bytes)
        print(f"  Saved: {sample} ({sample.stat().st_size:,} bytes)")

        # Also save as copy
        copy_dest = COPY_PATH.with_suffix(ext)
        shutil.copy2(sample, copy_dest)
        print(f"  Copied: {copy_dest}")

        print("\nDone.")
        return

    raise RuntimeError("All Gemini models failed.")


if __name__ == "__main__":
    main()
