#!/usr/bin/env python3
"""Export Navi PDF page references and cropped reusable image assets.

The page PNGs are reference-only. Mobile screens must rebuild UI with native
React Native components and import only cropped assets from assets/navi/*.
"""

from __future__ import annotations

import argparse
from pathlib import Path
from typing import Iterable, NamedTuple

try:
    import fitz  # PyMuPDF
    from PIL import Image, ImageDraw, ImageFont
except ImportError as exc:  # pragma: no cover - this is a local tooling helper.
    raise SystemExit(
        "Missing extraction dependencies. Install with: "
        "python3 -m pip install --user pymupdf pillow"
    ) from exc


PAGE_NAMES = [
    "splash",
    "onboarding-discover",
    "onboarding-planner",
    "onboarding-services",
    "login",
    "register",
    "home",
    "discovery",
    "luxury-stays",
    "experiences",
    "taxi",
    "food",
    "pharmacy",
    "grocery",
    "sim-cards",
    "emergency",
    "profile",
    "saved-destinations",
    "image-translator",
    "trip-planner-step-1",
    "hotel-detail",
    "trip-planner-step-2",
    "select-room",
    "trip-planner-step-3",
    "itinerary-result",
]


FOLDERS = [
    "pdf-pages",
    "extracted",
    "logos",
    "onboarding",
    "destinations",
    "hotels",
    "experiences",
    "services",
    "food",
    "pharmacy",
    "grocery",
    "sim",
    "profile",
    "translator",
    "trip-planner",
    "placeholders",
]


class CropSpec(NamedTuple):
    page: int
    folder: str
    filename: str
    bbox: tuple[float, float, float, float]


CROPS: list[CropSpec] = [
    # Logo and brand
    CropSpec(1, "logos", "navi-logo-mark.png", (148, 317, 242, 412)),
    CropSpec(5, "logos", "navi-app-icon.png", (135, 30, 255, 150)),
    CropSpec(1, "logos", "navi-compass-icon.png", (101, 295, 289, 484)),
    # Onboarding
    CropSpec(2, "onboarding", "onboarding-burj-khalifa.png", (15.8, 76, 374.2, 523.5)),
    CropSpec(3, "onboarding", "onboarding-map-planner.png", (22, 208, 368, 463)),
    CropSpec(4, "onboarding", "onboarding-delivery-scooter.png", (16, 84, 374, 352.5)),
    # Home
    CropSpec(7, "destinations", "home-hero-emirates.png", (16, 96.3, 374, 353.7)),
    CropSpec(7, "destinations", "home-rak-offer.png", (12, 313, 378, 438)),
    CropSpec(7, "experiences", "home-desert-safari.png", (16, 725.5, 374, 918.5)),
    CropSpec(7, "experiences", "home-grand-mosque.png", (17, 1086.9, 295, 1279.1)),
    CropSpec(7, "experiences", "home-marina-cruise.png", (16.2, 1585.3, 374.2, 1814.3)),
    # Discovery
    CropSpec(8, "destinations", "discovery-al-maha.png", (17, 243.4, 373, 436.6)),
    CropSpec(8, "destinations", "discovery-burj-khalifa.png", (17, 592.4, 373, 785.6)),
    CropSpec(8, "destinations", "discovery-museum-future.png", (17, 941.4, 373, 1134.6)),
    CropSpec(8, "destinations", "discovery-old-dubai-food.png", (17, 1290.4, 373, 1483.6)),
    CropSpec(8, "destinations", "discovery-marina-yacht.png", (17, 1639.4, 373, 1832.6)),
    CropSpec(8, "destinations", "discovery-al-ain-oasis.png", (17, 1988.4, 373, 2181.6)),
    # Hotels
    CropSpec(9, "hotels", "hotel-atlantis-royal-card.png", (55, 270.4, 411, 527.6)),
    CropSpec(9, "hotels", "hotel-qasr-al-sarab-card.png", (55, 767.4, 411, 1024.6)),
    CropSpec(21, "hotels", "hotel-atlantis-detail-hero.png", (45.3, 16, 404.7, 442)),
    CropSpec(21, "hotels", "hotel-atlantis-map-preview.png", (54, 1763.8, 396, 2020.2)),
    CropSpec(23, "hotels", "hotel-select-room-hero.png", (37, 80.4, 393, 337.6)),
    CropSpec(23, "hotels", "room-sky-view-suite.png", (37, 685.4, 393, 974.6)),
    CropSpec(23, "hotels", "room-palm-vista.png", (37, 1521.4, 393, 1810.6)),
    # Experiences
    CropSpec(10, "experiences", "experience-desert-safari.png", (35.9, 265, 324.1, 625)),
    CropSpec(10, "experiences", "experience-burj-khalifa.png", (300, 265, 430, 625)),
    CropSpec(10, "experiences", "category-theme-parks.png", (36, 773, 207, 869)),
    CropSpec(10, "experiences", "category-wellness.png", (223, 773, 394, 869)),
    CropSpec(10, "experiences", "category-culture.png", (36, 885, 207, 981.5)),
    CropSpec(10, "experiences", "category-water-tours.png", (223, 885, 394, 981.5)),
    # Taxi
    CropSpec(11, "services", "taxi-map-preview.png", (16, 80, 374, 330)),
    # Food
    CropSpec(12, "food", "food-golden-grill.png", (37, 249.4, 393, 442.6)),
    CropSpec(12, "food", "food-pasta-pizza.png", (37, 577.4, 393, 770.6)),
    CropSpec(12, "food", "food-zen-sushi.png", (37, 905.4, 393, 1098.6)),
    # Pharmacy
    CropSpec(13, "pharmacy", "pharmacy-prescription-card-bg.png", (14, 84, 376, 136)),
    CropSpec(13, "pharmacy", "pharmacy-multivitamin.png", (29, 618.7, 93, 682.7)),
    CropSpec(13, "pharmacy", "pharmacy-pain-relief.png", (29, 724.7, 93, 788.7)),
    # Grocery
    CropSpec(14, "grocery", "grocery-strawberries.png", (21, 248.5, 190, 377)),
    CropSpec(14, "grocery", "grocery-avocado.png", (208, 248.5, 377, 377)),
    CropSpec(14, "grocery", "grocery-milk.png", (21, 558.5, 190, 687)),
    CropSpec(14, "grocery", "grocery-eggs.png", (208, 558.5, 377, 687)),
    CropSpec(14, "grocery", "grocery-free-delivery-banner.png", (32, 925.5, 150.7, 981.5)),
    CropSpec(14, "grocery", "grocery-olive-oil.png", (21, 1060.5, 190, 1189)),
    # SIM
    CropSpec(15, "sim", "sim-hero-banner.png", (36, 96.8, 378, 243.8)),
    # Profile
    CropSpec(17, "profile", "profile-avatar-sample.png", (163, 101, 267, 205)),
    # Saved destinations
    CropSpec(18, "destinations", "saved-burj-khalifa.png", (17, 249, 373, 449.2)),
    CropSpec(18, "destinations", "saved-grand-mosque.png", (17, 614.8, 373, 815)),
    CropSpec(18, "destinations", "saved-al-marmoom.png", (17, 980.5, 373, 1180.8)),
    CropSpec(18, "destinations", "saved-hatta-dam.png", (17, 1397.7, 215, 1526.2)),
    CropSpec(18, "destinations", "saved-museum-future.png", (220, 1397.7, 373, 1526.2)),
    # Translator
    CropSpec(19, "translator", "translator-camera-preview.png", (15.8, 153, 374.2, 559)),
    # Trip planner
    CropSpec(20, "trip-planner", "planner-dubai.png", (63.6, 367.5, 227.4, 571.2)),
    CropSpec(20, "trip-planner", "planner-abu-dhabi.png", (242.6, 367.5, 406.4, 571.2)),
    CropSpec(20, "trip-planner", "planner-sharjah.png", (63.6, 587.2, 227.4, 791)),
    CropSpec(20, "trip-planner", "planner-rak.png", (242.6, 587.2, 406.4, 791)),
    CropSpec(20, "trip-planner", "planner-fujairah.png", (63.6, 807, 227.4, 1010.8)),
    CropSpec(22, "trip-planner", "planner-luxury.png", (64, 633, 229.6, 953)),
    CropSpec(22, "trip-planner", "planner-adventure.png", (241, 632.5, 406, 787.5)),
    CropSpec(22, "trip-planner", "planner-food-drink.png", (241, 799, 406, 953.5)),
    CropSpec(24, "trip-planner", "planner-journey-quote.png", (44, 869.8, 386, 1062.2)),
    # Itinerary
    CropSpec(25, "trip-planner", "itinerary-hero.png", (44, 95.7, 386, 396.3)),
    CropSpec(25, "trip-planner", "itinerary-villa.png", (109, 652.5, 385, 845.5)),
    CropSpec(25, "trip-planner", "itinerary-restaurant.png", (109, 1062.5, 385, 1255.5)),
    CropSpec(25, "trip-planner", "itinerary-pompeii.png", (109, 1600.2, 385, 1856.8)),
    CropSpec(25, "trip-planner", "itinerary-map.png", (53, 2861.8, 377, 3054.2)),
]


def ensure_dirs(root: Path) -> None:
    for folder in FOLDERS:
        (root / folder).mkdir(parents=True, exist_ok=True)


def page_png_name(page_number: int) -> str:
    return f"page-{page_number:02d}-{PAGE_NAMES[page_number - 1]}.png"


def render_page(page: fitz.Page, out_path: Path, zoom: float) -> Image.Image:
    pix = page.get_pixmap(matrix=fitz.Matrix(zoom, zoom), alpha=False)
    pix.save(out_path)
    return Image.open(out_path).convert("RGB")


def scaled_bbox(bbox: tuple[float, float, float, float], zoom: float) -> tuple[int, int, int, int]:
    x0, y0, x1, y1 = bbox
    return (round(x0 * zoom), round(y0 * zoom), round(x1 * zoom), round(y1 * zoom))


def write_placeholder(out_path: Path, label: str, size: tuple[int, int] = (800, 520)) -> None:
    image = Image.new("RGB", size, "#EAF3FF")
    draw = ImageDraw.Draw(image)
    draw.rectangle((0, 0, size[0], size[1]), fill="#EAF3FF")
    draw.ellipse((size[0] - 220, -80, size[0] + 80, 220), fill="#CFE3FF")
    draw.rectangle((40, size[1] - 150, size[0] - 40, size[1] - 80), fill="#FFFFFF")
    try:
        font = ImageFont.truetype("Arial.ttf", 32)
    except OSError:
        font = ImageFont.load_default()
    draw.text((48, size[1] - 135), label, fill="#1A73E8", font=font)
    image.save(out_path)


def export_pages(doc: fitz.Document, root: Path, zoom: float) -> list[Image.Image]:
    rendered: list[Image.Image] = []
    for index, page in enumerate(doc, start=1):
        out_path = root / "pdf-pages" / page_png_name(index)
        rendered.append(render_page(page, out_path, zoom))
    return rendered


def export_crops(rendered_pages: list[Image.Image], root: Path, zoom: float, specs: Iterable[CropSpec]) -> None:
    for spec in specs:
        out_path = root / spec.folder / spec.filename
        page_image = rendered_pages[spec.page - 1]
        crop_box = scaled_bbox(spec.bbox, zoom)
        crop = page_image.crop(crop_box)
        if crop.width < 48 or crop.height < 48:
            write_placeholder(out_path, spec.filename.removesuffix(".png"))
            continue
        crop.save(out_path)


def main() -> None:
    parser = argparse.ArgumentParser(description="Export Navi PDF pages and cropped assets.")
    parser.add_argument("--pdf", default="docs/design/Navi_compressed.pdf", help="Source Navi PDF path.")
    parser.add_argument("--assets-root", default="assets/navi", help="Output asset root.")
    parser.add_argument("--zoom", type=float, default=2.0, help="Render scale. 2.0 is enough for RN assets.")
    args = parser.parse_args()

    pdf_path = Path(args.pdf)
    assets_root = Path(args.assets_root)
    if not pdf_path.exists():
        fallback = Path("/Users/start-tech/Downloads/Navi_compressed.pdf")
        if fallback.exists():
            pdf_path = fallback
        else:
            raise SystemExit(f"Navi PDF not found at {pdf_path}")

    ensure_dirs(assets_root)
    doc = fitz.open(pdf_path)
    if doc.page_count != len(PAGE_NAMES):
        raise SystemExit(f"Expected 25 pages, found {doc.page_count}")

    rendered_pages = export_pages(doc, assets_root, args.zoom)
    export_crops(rendered_pages, assets_root, args.zoom, CROPS)
    print(f"Exported {len(rendered_pages)} PDF page PNGs to {assets_root / 'pdf-pages'}")
    print(f"Exported {len(CROPS)} cropped assets to {assets_root}")


if __name__ == "__main__":
    main()
