"""Jinja → HTML → Playwright headless screenshot (Windows worker version).

NAS DB·db.py 의존성 제거. slate 데이터는 worker가 NAS HTTP API에서 fetch해서
인자로 전달. 결과 PNG는 INSTA_MEDIA_ROOT (/mnt/nas/webpage/data/insta/)에 직접 저장.
"""
from __future__ import annotations

import asyncio
import json
import logging
import os
import tempfile
from pathlib import Path
from typing import Any, Dict, List

from jinja2 import Environment, FileSystemLoader, select_autoescape
from playwright.async_api import async_playwright

CARD_TEMPLATE_DIR = os.getenv("CARD_TEMPLATE_DIR", "/app/templates")
INSTA_MEDIA_ROOT = os.getenv("INSTA_MEDIA_ROOT", "/mnt/nas/webpage/data/insta")

logger = logging.getLogger(__name__)


# Chromium 동시 1개 (CPU·GPU 보호)
_RENDER_SEMAPHORE: asyncio.Semaphore | None = None


def _render_semaphore() -> asyncio.Semaphore:
    global _RENDER_SEMAPHORE
    if _RENDER_SEMAPHORE is None:
        _RENDER_SEMAPHORE = asyncio.Semaphore(1)
    return _RENDER_SEMAPHORE


# Browser pool — 매 슬레이트마다 launch X. 모듈 레벨 lazy + reuse.
_PLAYWRIGHT = None
_BROWSER = None


async def init_browser() -> None:
    global _PLAYWRIGHT, _BROWSER
    if _BROWSER is not None and _BROWSER.is_connected():
        return
    _PLAYWRIGHT = await async_playwright().start()
    _BROWSER = await _PLAYWRIGHT.chromium.launch()
    logger.info("Chromium browser pool 초기화 완료")


async def shutdown_browser() -> None:
    global _PLAYWRIGHT, _BROWSER
    if _BROWSER is not None:
        try:
            await _BROWSER.close()
        except Exception:
            logger.exception("browser close 중 예외 (무시)")
        _BROWSER = None
    if _PLAYWRIGHT is not None:
        try:
            await _PLAYWRIGHT.stop()
        except Exception:
            logger.exception("playwright stop 중 예외 (무시)")
        _PLAYWRIGHT = None


async def _get_browser():
    global _BROWSER
    if _BROWSER is None or not _BROWSER.is_connected():
        await init_browser()
    return _BROWSER


def _env() -> Environment:
    return Environment(
        loader=FileSystemLoader(CARD_TEMPLATE_DIR),
        autoescape=select_autoescape(["html", "j2"]),
    )


def _coerce(value, default):
    """NAS API는 cover_copy/body_copies/cta_copy를 dict/list로 반환하지만
    구버전 호환을 위해 JSON 문자열도 처리."""
    if value is None or value == "":
        return default
    if isinstance(value, str):
        try:
            return json.loads(value)
        except (ValueError, TypeError):
            return default
    return value


def _build_pages(slate: dict) -> List[dict]:
    """slate dict → 10 page specs."""
    cover = _coerce(slate.get("cover_copy"), {})
    bodies = _coerce(slate.get("body_copies"), [])
    cta = _coerce(slate.get("cta_copy"), {})
    accent = cover.get("accent_color") or "#0F62FE"
    pages: List[dict] = []
    pages.append({
        "page_type": "cover", "page_no": 1, "total_pages": 10,
        "headline": cover.get("headline", ""), "body": cover.get("body", ""),
        "accent_color": accent, "cta": "",
    })
    for i, b in enumerate(bodies[:8]):
        pages.append({
            "page_type": "body", "page_no": i + 2, "total_pages": 10,
            "headline": b.get("headline", ""), "body": b.get("body", ""),
            "accent_color": accent, "cta": "",
        })
    pages.append({
        "page_type": "cta", "page_no": 10, "total_pages": 10,
        "headline": cta.get("headline", ""), "body": cta.get("body", ""),
        "accent_color": accent, "cta": cta.get("cta", ""),
    })
    return pages


def _slate_dir(slate_id: int) -> str:
    out = os.path.join(INSTA_MEDIA_ROOT, str(slate_id))
    os.makedirs(out, exist_ok=True)
    return out


async def render_slate(slate: dict, slate_id: int, template: str = "default/card.html.j2") -> List[str]:
    """slate 데이터 + slate_id로 10장 PNG 렌더. 결과 path list 반환."""
    async with _render_semaphore():
        return await _render_slate_locked(slate, slate_id, template)


async def _render_slate_locked(slate: dict, slate_id: int, template: str) -> List[str]:
    env = _env()
    template_full = Path(CARD_TEMPLATE_DIR) / template
    if not template_full.exists():
        logger.warning("Template '%s' 없음 → default/card.html.j2 폴백", template)
        template = "default/card.html.j2"

    tmpl = env.get_template(template)
    pages = _build_pages(slate)
    out_dir = _slate_dir(slate_id)
    paths: List[str] = []

    browser = await _get_browser()
    ctx = await browser.new_context(viewport={"width": 1080, "height": 1350})
    try:
        page = await ctx.new_page()
        for spec in pages:
            html_str = tmpl.render(**spec)
            with tempfile.NamedTemporaryFile("w", suffix=".html", delete=False, encoding="utf-8") as f:
                f.write(html_str)
                html_path = f.name
            try:
                await page.goto(f"file://{html_path}", wait_until="networkidle")
                out_path = os.path.join(out_dir, f"{spec['page_no']:02d}.png")
                await page.screenshot(path=out_path, full_page=False, omit_background=False)
                paths.append(out_path)
            finally:
                try:
                    os.unlink(html_path)
                except OSError:
                    pass
    finally:
        await ctx.close()
    return paths
