from __future__ import annotations

import json
import math
import subprocess
import zipfile
from pathlib import Path

from PIL import Image, ImageDraw, ImageFont


ROOT = Path(__file__).resolve().parents[1]
XLSX = ROOT / "source-docs" / "周报0605.xlsx"
PDF = ROOT / "source-docs" / "纪要_产品标准化与AI赋能周会纪要.pdf"
IMAGE_DIR = ROOT / "images"
XLSX_IMAGE_DIR = IMAGE_DIR / "xlsx-media"
PDF_IMAGE_DIR = IMAGE_DIR / "pdf-pages"
CONTACT = IMAGE_DIR / "xlsx-media-contact-sheet.png"
MANIFEST = ROOT / "extracted" / "image-manifest.json"


def safe_font(size: int) -> ImageFont.FreeTypeFont | ImageFont.ImageFont:
    candidates = [
        "/System/Library/Fonts/PingFang.ttc",
        "/System/Library/Fonts/Supplemental/Arial Unicode.ttf",
        "/System/Library/Fonts/Helvetica.ttc",
    ]
    for candidate in candidates:
        if Path(candidate).exists():
            return ImageFont.truetype(candidate, size=size)
    return ImageFont.load_default()


def extract_xlsx_media() -> list[dict]:
    XLSX_IMAGE_DIR.mkdir(parents=True, exist_ok=True)
    manifest: list[dict] = []
    with zipfile.ZipFile(XLSX) as zf:
        names = [
            n
            for n in zf.namelist()
            if n.startswith("xl/media/") and not n.endswith("/")
        ]
        for idx, name in enumerate(sorted(names), start=1):
            suffix = Path(name).suffix.lower()
            out = XLSX_IMAGE_DIR / f"{idx:02d}-{Path(name).name}"
            out.write_bytes(zf.read(name))
            with Image.open(out) as im:
                width, height = im.size
                mode = im.mode
            manifest.append(
                {
                    "index": idx,
                    "source": name,
                    "path": str(out.relative_to(ROOT)),
                    "width": width,
                    "height": height,
                    "mode": mode,
                    "size": out.stat().st_size,
                    "suffix": suffix,
                }
            )
    return manifest


def render_pdf_pages() -> list[dict]:
    PDF_IMAGE_DIR.mkdir(parents=True, exist_ok=True)
    prefix = PDF_IMAGE_DIR / "meeting-page"
    subprocess.run(
        [
            "/Users/jack/.cache/codex-runtimes/codex-primary-runtime/dependencies/bin/pdftoppm",
            "-png",
            "-r",
            "180",
            str(PDF),
            str(prefix),
        ],
        check=True,
    )
    pages = []
    for idx, image_path in enumerate(sorted(PDF_IMAGE_DIR.glob("meeting-page-*.png")), 1):
        with Image.open(image_path) as im:
            width, height = im.size
        target = PDF_IMAGE_DIR / f"meeting-page-{idx:02d}.png"
        if image_path != target:
            image_path.rename(target)
            image_path = target
        pages.append(
            {
                "index": idx,
                "path": str(image_path.relative_to(ROOT)),
                "width": width,
                "height": height,
                "size": image_path.stat().st_size,
            }
        )
    return pages


def make_contact_sheet(items: list[dict]) -> None:
    thumb_w, thumb_h = 260, 170
    label_h = 58
    pad = 18
    cols = 4
    rows = math.ceil(len(items) / cols)
    sheet = Image.new(
        "RGB",
        (
            cols * (thumb_w + pad) + pad,
            rows * (thumb_h + label_h + pad) + pad,
        ),
        "#f8fafc",
    )
    draw = ImageDraw.Draw(sheet)
    font = safe_font(18)
    small = safe_font(13)
    for i, item in enumerate(items):
        r, c = divmod(i, cols)
        x = pad + c * (thumb_w + pad)
        y = pad + r * (thumb_h + label_h + pad)
        image_path = ROOT / item["path"]
        with Image.open(image_path) as im:
            im = im.convert("RGB")
            im.thumbnail((thumb_w, thumb_h))
            frame = Image.new("RGB", (thumb_w, thumb_h), "white")
            fx = (thumb_w - im.width) // 2
            fy = (thumb_h - im.height) // 2
            frame.paste(im, (fx, fy))
        draw.rounded_rectangle(
            [x - 2, y - 2, x + thumb_w + 2, y + thumb_h + label_h + 2],
            radius=8,
            fill="white",
            outline="#cbd5e1",
        )
        sheet.paste(frame, (x, y))
        draw.text((x + 8, y + thumb_h + 8), f"{item['index']:02d} {Path(item['path']).name}", fill="#0f172a", font=font)
        draw.text((x + 8, y + thumb_h + 33), f"{item['width']}x{item['height']}  {item['size']//1024}KB", fill="#475569", font=small)
    sheet.save(CONTACT)


def main() -> None:
    MANIFEST.parent.mkdir(parents=True, exist_ok=True)
    xlsx_images = extract_xlsx_media()
    pdf_pages = render_pdf_pages()
    make_contact_sheet(xlsx_images)
    manifest = {
        "xlsx_images": xlsx_images,
        "pdf_pages": pdf_pages,
        "contact_sheet": str(CONTACT.relative_to(ROOT)),
    }
    MANIFEST.write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8")
    print(json.dumps(manifest, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()
