#!/usr/bin/env python3
"""Generate readable ONEPAGER.html for each project package and an optional GALLERY.html index.

Works with the project_package template created for RCA/Goldsmiths.

Usage:
  source .venv_rca/bin/activate
  python tools/media_onepager.py --root ~/Desktop/RCA_MediaLibrary/innovation-design-engineering-ma-msc/2025

It will:
- Find projects/*/01_text/project_profile.yaml
- Render ONEPAGER.html at project root
- Render 00_index/GALLERY.html at year root

Safe: local file operations only.
"""

import argparse
import html
import os
from pathlib import Path
from urllib.parse import quote

import yaml


def read_text(p: Path) -> str:
    try:
        return p.read_text(encoding="utf-8")
    except Exception:
        return ""


def relpath(from_dir: Path, to_path: Path) -> str:
    return os.path.relpath(to_path, start=from_dir)


def esc(s: str) -> str:
    return html.escape(s or "")


def list_images(originals_dir: Path):
    if not originals_dir.exists():
        return []
    imgs = sorted([p for p in originals_dir.iterdir() if p.is_file() and p.name.lower().startswith("img_")])
    return imgs


def yaml_load(p: Path) -> dict:
    try:
        return yaml.safe_load(p.read_text(encoding="utf-8")) or {}
    except Exception:
        return {}


def pick(d: dict, path: str, default=""):
    cur = d
    for k in path.split("."):
        if not isinstance(cur, dict) or k not in cur:
            return default
        cur = cur[k]
    return cur if cur is not None else default


def to_list(v):
    if v is None:
        return []
    if isinstance(v, list):
        return v
    if isinstance(v, str) and v.strip():
        return [v.strip()]
    return []


def render_onepager(project_dir: Path) -> dict:
    profile_path = project_dir / "01_text" / "project_profile.yaml"
    desc_path = project_dir / "01_text" / "project_description.md"
    links_path = project_dir / "01_text" / "links.md"
    source_url = read_text(project_dir / "00_admin" / "source_url.txt").strip()

    prof = yaml_load(profile_path)

    title = pick(prof, "identifiers.project_title", "") or project_dir.name
    subtitle = pick(prof, "identifiers.project_subtitle", "")
    program = pick(prof, "identifiers.program", "")
    year = str(pick(prof, "identifiers.grad_year", ""))
    school = pick(prof, "identifiers.school", "")

    authors = prof.get("authors") or []
    author_names = [a.get("name", "") for a in authors if isinstance(a, dict) and a.get("name")]

    materials = to_list(pick(prof, "project.materials_tech", []))
    themes = to_list(pick(prof, "project.themes", []))
    kw_cn = to_list(pick(prof, "project.keywords_cn", []))
    kw_en = to_list(pick(prof, "project.keywords_en", []))

    contacts = prof.get("contacts") or {}
    contact_lines = []
    for k in ["email", "phone", "instagram", "xhs", "website", "linkedin"]:
        v = contacts.get(k)
        if v:
            contact_lines.append((k, str(v)))

    originals_dir = project_dir / "02_images" / "originals"
    imgs = list_images(originals_dir)

    desc_md = read_text(desc_path)
    links_md = read_text(links_path)

    # Very simple MD->HTML: preserve as <pre> (readable, zero deps)
    def pre_block(label, txt):
        if not txt.strip():
            return ""
        return f"<h2>{esc(label)}</h2><pre>{esc(txt)}</pre>"

    img_html = []
    for p in imgs:
        rel = relpath(project_dir, p)
        img_html.append(
            f"<figure><img loading='lazy' src='{quote(rel)}' alt='{esc(p.name)}'/><figcaption>{esc(p.name)}</figcaption></figure>"
        )

    html_out = f"""<!doctype html>
<html lang="zh">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>{esc(title)}</title>
<style>
  body{{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Arial; margin:24px; line-height:1.55; max-width:1100px}}
  .meta{{display:grid; grid-template-columns: 1fr 1fr; gap:16px; margin:16px 0 24px;}}
  .card{{border:1px solid #ddd; border-radius:10px; padding:14px; background:#fafafa}}
  h1{{margin:0 0 6px; font-size:28px}}
  .subtitle{{color:#555; margin:0 0 10px}}
  .tags span{{display:inline-block; padding:2px 8px; border:1px solid #ddd; border-radius:999px; margin:2px 6px 2px 0; font-size:12px; background:white}}
  pre{{white-space:pre-wrap; background:#0b1020; color:#e8e8e8; padding:12px; border-radius:10px; overflow:auto}}
  figure{{margin:16px 0}}
  img{{max-width:100%; height:auto; border-radius:10px; border:1px solid #eee}}
  figcaption{{color:#666; font-size:12px; margin-top:6px}}
  a{{color:#0b57d0}}
</style>
</head>
<body>
  <h1>{esc(title)}</h1>
  <p class="subtitle">{esc(subtitle)}</p>

  <div class="meta">
    <div class="card">
      <h2>Basic</h2>
      <p><b>School</b>: {esc(school)}<br/>
         <b>Program</b>: {esc(program)}<br/>
         <b>Year</b>: {esc(year)}<br/>
         <b>Author(s)</b>: {esc(', '.join(author_names))}</p>
      <p><b>Source</b>: {f"<a href='{esc(source_url)}' target='_blank'>{esc(source_url)}</a>" if source_url else ""}</p>
    </div>
    <div class="card">
      <h2>Materials / Themes / Keywords</h2>
      <div class="tags">
        {''.join([f"<span>{esc(x)}</span>" for x in materials])}
      </div>
      <div class="tags">
        {''.join([f"<span>{esc(x)}</span>" for x in themes])}
      </div>
      <div class="tags">
        {''.join([f"<span>{esc(x)}</span>" for x in (kw_cn+kw_en)])}
      </div>
    </div>
    <div class="card">
      <h2>Contacts</h2>
      <ul>
        {''.join([f"<li><b>{esc(k)}</b>: {esc(v)}</li>" for k,v in contact_lines]) or '<li>(empty)</li>'}
      </ul>
    </div>
    <div class="card">
      <h2>Files</h2>
      <ul>
        <li>Images: {len(imgs)}</li>
        <li>Description: {('yes' if desc_md.strip() else 'no')}</li>
        <li>Links: {('yes' if links_md.strip() else 'no')}</li>
      </ul>
    </div>
  </div>

  <h2>Images</h2>
  {''.join(img_html) if img_html else '<p>(no images downloaded yet)</p>'}

  {pre_block('Description (Markdown extracted)', desc_md)}
  {pre_block('Links (Markdown)', links_md)}

</body>
</html>
"""

    out_path = project_dir / "ONEPAGER.html"
    out_path.write_text(html_out, encoding="utf-8")

    cover = imgs[0] if imgs else None

    return {
        "title": title,
        "author": ", ".join(author_names),
        "year": year,
        "program": program,
        "project_dir": str(project_dir),
        "onepager": str(out_path),
        "cover_rel": relpath(project_dir, cover) if cover else "",
        "source_url": source_url,
        "image_count": len(imgs),
    }


def render_gallery(year_root: Path, items: list):
    idx_dir = year_root / "00_index"
    ensure_dir(idx_dir)
    cards = []
    for it in items:
        proj_dir = Path(it["project_dir"])
        onepager = proj_dir / "ONEPAGER.html"
        rel_onepager = relpath(idx_dir, onepager)
        cover_rel = it.get("cover_rel")
        cover_from_idx = relpath(idx_dir, proj_dir / cover_rel) if cover_rel else ""
        img_tag = f"<img loading='lazy' src='{quote(cover_from_idx)}' alt='{esc(it['title'])}'/>" if cover_rel else "<div class='ph'>(no cover)</div>"
        cards.append(f"""
        <a class='card' href='{quote(rel_onepager)}'>
          <div class='cover'>{img_tag}</div>
          <div class='txt'>
            <div class='t'>{esc(it['title'])}</div>
            <div class='m'>{esc(it.get('author',''))}</div>
            <div class='s'>{esc(it.get('program',''))} · {esc(it.get('year',''))} · {it.get('image_count',0)} imgs</div>
          </div>
        </a>
        """)

    html_out = f"""<!doctype html>
<html lang='zh'>
<head>
<meta charset='utf-8'/>
<meta name='viewport' content='width=device-width,initial-scale=1'/>
<title>Gallery</title>
<style>
  body{{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Arial; margin:24px;}}
  .grid{{display:grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap:14px;}}
  .card{{display:block; border:1px solid #e5e5e5; border-radius:12px; overflow:hidden; text-decoration:none; color:#111; background:#fff}}
  .cover{{aspect-ratio: 4/3; background:#f3f3f3; display:flex; align-items:center; justify-content:center; overflow:hidden}}
  .cover img{{width:100%; height:100%; object-fit:cover}}
  .ph{{color:#666; font-size:12px}}
  .txt{{padding:10px 12px}}
  .t{{font-weight:700; font-size:14px; margin-bottom:4px}}
  .m{{color:#444; font-size:12px; margin-bottom:3px}}
  .s{{color:#777; font-size:11px}}
</style>
</head>
<body>
<h1>Gallery</h1>
<p>{len(items)} projects</p>
<div class='grid'>
{''.join(cards)}
</div>
</body>
</html>
"""

    out_path = idx_dir / "GALLERY.html"
    out_path.write_text(html_out, encoding="utf-8")


def ensure_dir(p: Path) -> None:
    p.mkdir(parents=True, exist_ok=True)


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--root", required=True, help="year root, e.g. .../2025")
    ap.add_argument("--no-gallery", action="store_true")
    args = ap.parse_args()

    year_root = Path(os.path.expanduser(args.root)).resolve()
    projects_dir = year_root / "projects"

    items = []
    if projects_dir.exists():
        for proj in sorted(projects_dir.iterdir()):
            if not proj.is_dir():
                continue
            prof = proj / "01_text" / "project_profile.yaml"
            if not prof.exists():
                continue
            try:
                it = render_onepager(proj)
                items.append(it)
            except Exception:
                continue

    if not args.no_gallery:
        render_gallery(year_root, items)


if __name__ == "__main__":
    main()
