"""
Pillow-based episode update card renderer.

Renders a 768×(768*4/3) card with a full-bleed cover image,
gradient overlay, and episode metadata overlaid at the bottom.
"""
from __future__ import annotations

import aiohttp
from PIL import Image, ImageDraw

from .font_manager import get_font
from .image_utils import (
    fetch_image,
    fit_cover,
    image_to_base64,
    make_gradient_overlay,
    placeholder_cover,
    strip_supplementary,
    text_line_height,
    text_width,
    wrap_text,
)

# ── Palette ────────────────────────────────────────────────────────────────────
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
PINK = (236, 72, 153)       # --accent-pink: #ec4899
WHITE_80 = (255, 255, 255, 204)
WHITE_85 = (255, 255, 255, 217)

# ── Layout constants ───────────────────────────────────────────────────────────
CARD_W = 768
CARD_H = int(CARD_W * 4 / 3)   # 1024


# ── Main renderer ──────────────────────────────────────────────────────────────

async def draw_episode_card(
    data: dict,
    session: aiohttp.ClientSession | None = None,
) -> str | None:
    """Render an episode update card and return a base64-encoded PNG string."""
    try:
        return await _render(data, session)
    except Exception as exc:
        try:
            from astrbot.api import logger
            logger.error(f"[-] Pillow episode card render failed: {exc}")
        except Exception:
            pass
        return None


async def _render(data: dict, session: aiohttp.ClientSession | None) -> str | None:
    image_url = str(data.get("image_url") or "")
    name = strip_supplementary(str(data.get("name") or ""))
    name_cn = strip_supplementary(str(data.get("name_cn") or ""))
    title = name_cn or name or ""
    desc = strip_supplementary(str(data.get("desc") or ""))
    sort_num = data.get("sort") or data.get("ep") or 1
    airdate = str(data.get("airdate") or "")
    comment = int(data.get("comment") or 0)

    # ── Fonts ──────────────────────────────────────────────────────────────────
    F = {
        "ep_num": get_font(52, bold=True),
        "title": get_font(44, bold=True),
        "meta": get_font(16, bold=True),
        "desc": get_font(16),
    }

    # ── Fetch cover image ──────────────────────────────────────────────────────
    cover_img = await fetch_image(image_url, session, timeout=10)

    # ── Base canvas (black) ────────────────────────────────────────────────────
    canvas = Image.new("RGBA", (CARD_W, CARD_H), (*BLACK, 255))

    if cover_img:
        cover = fit_cover(cover_img, CARD_W, CARD_H)
        canvas.alpha_composite(cover, (0, 0))
    else:
        # Fallback: dark radial-ish background
        placeholder = placeholder_cover(CARD_W, CARD_H, color=(42, 42, 53))
        canvas.alpha_composite(placeholder)

    # ── Gradient overlay ───────────────────────────────────────────────────────
    overlay = make_gradient_overlay(CARD_W, CARD_H, start_pct=0.4)
    canvas.alpha_composite(overlay)

    # ── Content overlay ────────────────────────────────────────────────────────
    d = ImageDraw.Draw(canvas)

    SIDE_PAD = 28
    content_x = SIDE_PAD
    content_bottom = CARD_H - 28

    # Build lines bottom-up
    # 1. Description (max 3 lines)
    desc_lines: list[str] = []
    if desc:
        desc_lines = wrap_text(desc, F["desc"], CARD_W - 2 * SIDE_PAD)[:3]

    LH_desc = int(text_line_height(F["desc"]) * 1.7)
    desc_block_h = len(desc_lines) * LH_desc + (24 if desc_lines else 0)

    # 2. Metadata row
    meta_parts: list[str] = []
    if airdate and "-" in airdate:
        meta_parts.append(airdate.split("-")[0])
    meta_parts.append("24min")
    if comment > 0:
        meta_parts.append(f"{comment} comments")
    meta_txt = "  |  ".join(meta_parts)
    meta_h = text_line_height(F["meta"]) + 20

    # 3. EP + Title row
    ep_txt = f"EP.{int(sort_num):02d}"
    ep_h = text_line_height(F["ep_num"])
    LH_title = text_line_height(F["title"]) + 6
    title_lines = wrap_text(title, F["title"], CARD_W - 2 * SIDE_PAD - text_width(ep_txt, F["ep_num"]) - 16)[:2]
    title_block_h = len(title_lines) * LH_title

    header_h = max(ep_h, title_block_h)

    # ── Draw from bottom up ────────────────────────────────────────────────────
    cur_y = content_bottom

    # Description
    if desc_lines:
        cur_y -= desc_block_h - LH_desc
        for line in reversed(desc_lines):
            d.text((content_x, cur_y), line, font=F["desc"], fill=WHITE_85)
            cur_y -= LH_desc
        cur_y -= 24

    # Metadata row
    cur_y -= meta_h
    d.text((content_x, cur_y), meta_txt, font=F["meta"], fill=(*WHITE[:3], 200))
    cur_y -= 20

    # EP + Title row
    ep_w = text_width(ep_txt, F["ep_num"])
    ep_y = cur_y - header_h
    d.text((content_x, ep_y), ep_txt, font=F["ep_num"], fill=(*PINK, 255))

    title_x = content_x + ep_w + 16
    title_available_w = CARD_W - title_x - SIDE_PAD
    # Re-wrap with accurate available width
    title_lines = wrap_text(title, F["title"], title_available_w)[:2]
    for i, line in enumerate(title_lines):
        d.text((title_x, ep_y + i * LH_title), line, font=F["title"], fill=WHITE)

    return image_to_base64(canvas)
