#!/usr/bin/env python3
"""
PPT Master - Native Template Structure Contract

Build a portable master/layout contract from the PPTX template import manifest.

Usage:
    Imported by pptx_template_import.py.

Examples:
    write_native_structure_bundle(source_pptx, output_dir, manifest)

Dependencies:
    None (only uses standard library)
"""

from __future__ import annotations

import hashlib
import json
import shutil
from pathlib import Path
from typing import Any


SCHEMA = "ppt-master.native-structure.v1"
SOURCE_TEMPLATE_NAME = "source_template.pptx"
CONTRACT_NAME = "native_structure.json"


def _sha256(path: Path) -> str:
    digest = hashlib.sha256()
    with path.open("rb") as handle:
        for chunk in iter(lambda: handle.read(1024 * 1024), b""):
            digest.update(chunk)
    return digest.hexdigest()


def _copy_source_template(source: Path, destination: Path) -> None:
    if source.resolve() == destination.resolve():
        return
    shutil.copy2(source, destination)


def _has_reusable_structure(manifest: dict[str, Any]) -> bool:
    layouts = manifest.get("layouts", [])
    masters = manifest.get("masters", [])
    slides = manifest.get("slides", [])
    used_layouts = [layout for layout in layouts if layout.get("usedBySlides")]
    candidate_layouts = used_layouts or layouts
    if any(
        layout.get("backgroundAsset")
        or int(layout.get("drawableShapeCount") or 0) > 0
        or any(
            placeholder.get("semanticRole")
            not in {"date", "footer", "slide-number", "other"}
            for placeholder in layout.get("placeholders", [])
        )
        for layout in candidate_layouts
    ):
        return True
    if any(
        master.get("backgroundAsset")
        or int(master.get("drawableShapeCount") or 0) > 0
        or master.get("imageAssets")
        for master in masters
    ):
        return True
    return any(slide.get("placeholders") for slide in slides)


def build_native_structure(
    source_pptx: Path,
    manifest: dict[str, Any],
) -> dict[str, Any]:
    """Build the portable source-package structure contract."""
    masters = manifest.get("masters", [])
    layouts = manifest.get("layouts", [])
    slides = manifest.get("slides", [])
    master_key_by_path = {
        master["path"]: f"master_{index:02d}"
        for index, master in enumerate(masters, start=1)
    }
    layout_key_by_path = {
        layout["path"]: f"layout_{index:02d}"
        for index, layout in enumerate(layouts, start=1)
    }
    complete_graph = (
        bool(masters and layouts)
        and all(
            layout.get("parentPath") in master_key_by_path
            for layout in layouts
        )
        and all(
            slide.get("layoutPath") in layout_key_by_path
            and slide.get("masterPath") in master_key_by_path
            for slide in slides
        )
    )
    reusable_structure = _has_reusable_structure(manifest)
    recommended_mode = "preserve" if complete_graph and reusable_structure else "template"
    reasons: list[str] = []
    if not complete_graph:
        reasons.append("incomplete-master-layout-graph")
    if not reusable_structure:
        reasons.append("source-structure-is-minimal")
    if complete_graph and reusable_structure:
        reasons.append("source-master-layout-contract-is-reusable")
    if len(masters) > 1:
        reasons.append("source-uses-multiple-masters")

    master_contracts = []
    for master in masters:
        key = master_key_by_path[master["path"]]
        master_contracts.append({
            "key": key,
            "name": master.get("displayName") or master.get("name") or key,
            "packagePart": master["path"],
            "themePart": master.get("themePath"),
            "theme": master.get("theme") or {"colors": {}, "fonts": {}},
            "backgroundAsset": master.get("backgroundAsset"),
            "imageAssets": master.get("imageAssets", []),
            "drawableShapeCount": master.get("drawableShapeCount", 0),
            "layoutKeys": [
                layout_key_by_path[layout["path"]]
                for layout in layouts
                if layout.get("parentPath") == master["path"]
            ],
        })

    layout_contracts = []
    for layout in layouts:
        key = layout_key_by_path[layout["path"]]
        layout_contracts.append({
            "key": key,
            "name": layout.get("displayName") or layout.get("name") or key,
            "type": layout.get("layoutType"),
            "packagePart": layout["path"],
            "masterKey": master_key_by_path.get(layout.get("parentPath")),
            "backgroundAsset": layout.get("backgroundAsset"),
            "imageAssets": layout.get("imageAssets", []),
            "drawableShapeCount": layout.get("drawableShapeCount", 0),
            "placeholders": layout.get("placeholders", []),
            "usedBySlides": layout.get("usedBySlides", []),
            "svgFile": layout.get("svgFile"),
        })

    slide_contracts = []
    for slide in slides:
        slide_contracts.append({
            "index": slide["index"],
            "pageType": slide.get("pageType"),
            "layoutKey": layout_key_by_path.get(slide.get("layoutPath")),
            "masterKey": master_key_by_path.get(slide.get("masterPath")),
            "placeholders": slide.get("placeholders", []),
            "layeredSvgFile": slide.get("svgFile"),
            "flatSvgFile": slide.get("flatSvgFile"),
        })

    return {
        "schema": SCHEMA,
        "source": {
            "name": source_pptx.name,
            "templateFile": SOURCE_TEMPLATE_NAME,
            "sha256": _sha256(source_pptx),
        },
        "slideSize": manifest.get("slideSize", {}),
        "strategy": {
            "preservationEligible": complete_graph,
            "reusableStructureDetected": reusable_structure,
            "recommendedMode": recommended_mode,
            "recommendationScope": "source-structure-assessment",
            "templateOutputMode": "template",
            "downstreamTemplateAdherence": "strategist-confirmed-explicit-structure",
            "hasMultipleMasters": len(masters) > 1,
            "reasonCodes": reasons,
        },
        "masters": master_contracts,
        "layouts": layout_contracts,
        "slides": slide_contracts,
    }


def write_native_structure_bundle(
    source_pptx: Path,
    output_dir: Path,
    manifest: dict[str, Any],
) -> dict[str, Any]:
    """Copy the source template and write its portable structure contract."""
    source_copy = output_dir / SOURCE_TEMPLATE_NAME
    _copy_source_template(source_pptx, source_copy)
    contract = build_native_structure(source_pptx, manifest)
    (output_dir / CONTRACT_NAME).write_text(
        json.dumps(contract, ensure_ascii=False, indent=2) + "\n",
        encoding="utf-8",
    )
    return contract
