"""
render_brand_manual.py

Takes the manifest.json + PNGs produced by batch_generate.py for one client
and injects them into the brand manual HTML template as new application
pages, each image embedded as base64 so the final file is a single,
portable HTML document ready to hand to render_pdf.py.

Usage:
    python render_brand_manual.py \
        --template brand-manual-template.html \
        --client-output output/kai-cleaning-co \
        --client-name "KAI Cleaning Co." \
        --logo kai-full.png --logo-mark kai-icon.png \
        --out kai-brand-manual.html
"""

import argparse
import base64
import datetime
import html
import json
from collections import defaultdict
from pathlib import Path

from extract_palette import extract_palette, recolor_logo, image_to_data_uri, file_to_data_uri
from fonts import build_font_config

# Groups of mockup `type` values that share one application page, in the
# order they appear in the manual. Digital + packaging share a page to
# match the reference document's structure.
PAGE_GROUPS = [
    ("Uniforms", ["uniform"], "grid"),
    ("Vehicles", ["vehicle"], "wide"),
    ("Stationery", ["stationery"], "grid"),
    ("Digital & Packaging", ["digital", "packaging"], "grid"),
]

# label + one-line description per mockup_id, matching the reference doc's
# captions where a direct equivalent exists. Unknown ids fall back to a
# generic title-cased label with no description.
MOCKUP_META = {
    "tshirt-front":  ("Tee — Chest Logo", "Full-color horizontal lockup, left chest."),
    "polo-front":    ("Polo — Chest Logo", "Full-color horizontal lockup, left chest."),
    "cap-front":     ("Cap — Front Mark", "Icon mark only, embroidered front panel."),
    "sleeve-mark":   ("Sleeve — Icon Mark", "Small icon-only mark, upper sleeve."),
    "van-side":      ("Van — Side Panel", "Full-color horizontal lockup, centered across the side panel."),
    "sedan-side":    ("Sedan — Side Panel", "Compact horizontal lockup on rear door, scaled to panel width."),
    "letterhead":    ("Letterhead", "Full lockup, top-left header position."),
    "business-card": ("Business Card", "Full lockup with contact details."),
    "envelope":      ("Envelope", "Full lockup, return-address position."),
    "social-avatar": ("Social Avatar", "Icon mark, reversed, on Primary."),
    "social-banner": ("Social Banner", "Reversed lockup on Accent, left-aligned."),
    "spray-bottle":  ("Spray Bottle Label", "Vertical lockup centered at top, product name below."),
    "test-bottle":   ("Product Bottle", "Front label placement."),
}


def embed_image(path):
    data = Path(path).read_bytes()
    b64 = base64.b64encode(data).decode("ascii")
    ext = Path(path).suffix.lstrip(".").lower()
    mime = "jpeg" if ext == "jpg" else ext
    return f"data:image/{mime};base64,{b64}"


def build_application_page(page_num, label, items, client_output_dir, client_name, layout):
    page_id = "app-" + label.lower().replace(" & ", "-").replace(" ", "-")
    box_class = "app-box wide" if layout == "wide" else "app-box"
    col_class = "app-grid-2" if layout != "wide" else ""

    cards = []
    for item in items:
        img_path = Path(client_output_dir) / f"{item['mockup_id']}.png"
        if not img_path.exists():
            continue
        data_uri = embed_image(img_path)
        title, desc = MOCKUP_META.get(item["mockup_id"], (item["mockup_id"].replace("-", " ").title(), ""))
        desc_html = f'<p class="box-caption">{desc}</p>' if desc else ""
        cards.append(f"""
      <div>
        <div class="crop-box {box_class}">
          <span class="crop tl"></span><span class="crop tr"></span><span class="crop bl"></span><span class="crop br"></span>
          <img src="{data_uri}" alt="{title}">
        </div>
        <p class="box-label" style="margin-top:14px;">{title}</p>
        {desc_html}
      </div>""")

    cards_html = "".join(cards)
    wrapper_open = f'<div class="{col_class}">' if col_class else '<div style="display:flex; flex-direction:column; gap:28px;">'

    return page_id, f"""
  <div class="sheet" id="{page_id}">
    <p class="eyebrow">05 — Applications</p>
    <h1 class="page-title">{label}</h1>
    {wrapper_open}{cards_html}
    </div>
    <div class="meta-foot"><span>{client_name} — Brand guidelines</span><span>Page {page_num:02d}</span></div>
  </div>
"""


def render(template_path, client_output_dir, client_name, logo_path, out_path,
           heading_font_path=None, body_font_path=None, logo_mark_path=None):
    manifest_path = Path(client_output_dir) / "manifest.json"
    if not manifest_path.exists():
        raise SystemExit(
            f"No manifest.json found in {client_output_dir} -- run batch_generate.py for this client first."
        )
    results = json.loads(manifest_path.read_text())
    client_name_safe = html.escape(client_name)

    by_type = defaultdict(list)
    for r in results:
        by_type[r["type"]].append(r)

    template_html = Path(template_path).read_text()

    pages_html = []
    page_num = 8  # 7 static pages precede the application pages
    for label, type_list, layout in PAGE_GROUPS:
        items = []
        for t in type_list:
            items.extend(by_type.get(t, []))
        if not items:
            continue
        page_id, page_html = build_application_page(
            page_num, label, items, client_output_dir, client_name_safe, layout
        )
        pages_html.append(page_html)
        page_num += 1

    final_html = template_html.replace("<!--APPLICATION_PAGES-->", "\n".join(pages_html))
    final_html = final_html.replace("{{CLIENT_NAME}}", client_name_safe)
    final_html = final_html.replace("{{EDITION_DATE}}", datetime.date.today().strftime("%B %Y"))

    # --- logo + palette wiring ---
    palette = extract_palette(logo_path)
    logo_data_uri = file_to_data_uri(logo_path)
    mono_uri = image_to_data_uri(recolor_logo(logo_path, "#1A1A1A"))
    reversed_uri = image_to_data_uri(recolor_logo(logo_path, "#FFFFFF"))
    wrong_uri = image_to_data_uri(recolor_logo(logo_path, "#E619B0"))  # deliberately off-brand, for the misuse demo

    mark_source = logo_mark_path or logo_path
    mark_uri = file_to_data_uri(mark_source)

    # --- font wiring ---
    font_faces_css, heading_stack, body_stack, heading_name, body_name = build_font_config(
        heading_font_path, body_font_path
    )

    token_map = {
        "{{LOGO_DATA_URI}}": logo_data_uri,
        "{{LOGO_MONO_URI}}": mono_uri,
        "{{LOGO_REVERSED_URI}}": reversed_uri,
        "{{LOGO_WRONG_URI}}": wrong_uri,
        "{{LOGO_MARK_URI}}": mark_uri,
        "{{COLOR_PRIMARY}}": palette["primary"]["hex"],
        "{{COLOR_PRIMARY_RGB}}": palette["primary"]["rgb"],
        "{{COLOR_PRIMARY_DEEP}}": palette["primary_deep"]["hex"],
        "{{COLOR_PRIMARY_DEEP_RGB}}": palette["primary_deep"]["rgb"],
        "{{COLOR_ACCENT}}": palette["accent"]["hex"],
        "{{COLOR_ACCENT_RGB}}": palette["accent"]["rgb"],
        "{{FONT_FACES}}": font_faces_css,
        "{{FONT_HEADING_STACK}}": heading_stack,
        "{{FONT_BODY_STACK}}": body_stack,
        "{{FONT_HEADING_NAME}}": html.escape(heading_name),
        "{{FONT_BODY_NAME}}": html.escape(body_name),
    }
    for token, value in token_map.items():
        final_html = final_html.replace(token, value)

    Path(out_path).write_text(final_html)
    print(f"Extracted palette: primary={palette['primary']['hex']} deep={palette['primary_deep']['hex']} accent={palette['accent']['hex']}")
    print(f"Rendered {len(results)} mockup(s) across {len(pages_html)} application page(s), {page_num - 1} total pages: {out_path}")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Wire batch-generated mockups + logo palette into the brand manual template.")
    parser.add_argument("--template", required=True, help="Path to brand-manual-template.html")
    parser.add_argument("--client-output", required=True, help="Path to batch_generate.py's output/<client> folder")
    parser.add_argument("--client-name", required=True, help="Display name to use throughout the manual")
    parser.add_argument("--logo", required=True, help="Path to the client's full logo lockup (PNG, transparent bg recommended)")
    parser.add_argument("--logo-mark", help="Optional path to a standalone icon/mark file, used on the Icon Mark variant")
    parser.add_argument("--heading-font", help="Optional path to a custom heading/display font (OTF/TTF/WOFF/WOFF2)")
    parser.add_argument("--body-font", help="Optional path to a custom body font (OTF/TTF/WOFF/WOFF2)")
    parser.add_argument("--out", required=True, help="Output path for the final rendered HTML")
    args = parser.parse_args()

    render(args.template, args.client_output, args.client_name, args.logo, args.out,
           args.heading_font, args.body_font, args.logo_mark)
