"""Config and library.json readers for the build pipeline."""

from __future__ import annotations

import json
import sys
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple

if sys.version_info >= (3, 11):
    import tomllib
else:
    import tomli as tomllib


@dataclass(frozen=True)
class H5PConfig:
    """Parsed ``[tool.h5p]`` section from ``pyproject.toml``."""

    machine_name: str
    vendor_map: Dict[str, str]


@dataclass(frozen=True)
class LibraryInfo:
    """Parsed ``library.json`` data for a single vendor library."""

    machine_name: str
    major_version: int
    minor_version: int
    runnable: bool
    preloaded_js: Tuple[str, ...]
    preloaded_css: Tuple[str, ...]


def read_h5p_config(pyproject_path: Path) -> H5PConfig:
    """Read the ``[tool.h5p]`` section from a pyproject.toml.

    Parameters
    ----------
    pyproject_path:
        Path to the ``pyproject.toml`` file.

    Returns
    -------
    H5PConfig
        Parsed configuration.

    Raises
    ------
    KeyError
        If the ``[tool.h5p]`` section or required keys are missing.
    """
    with pyproject_path.open("rb") as f:
        data = tomllib.load(f)

    h5p = data["tool"]["h5p"]
    return H5PConfig(
        machine_name=h5p["machine_name"],
        vendor_map=dict(h5p.get("vendor", {})),
    )


def read_library_json(vendor_dir: Path) -> Optional[LibraryInfo]:
    """Read ``library.json`` from a vendor directory.

    Parameters
    ----------
    vendor_dir:
        Path to the vendor directory containing ``library.json``.

    Returns
    -------
    LibraryInfo or None
        Parsed library info, or ``None`` if the file does not exist.
    """
    path = vendor_dir / "library.json"
    if not path.exists():
        return None

    data = json.loads(path.read_text(encoding="utf-8"))

    js_files = tuple(
        entry["path"] for entry in data.get("preloadedJs", [])
    )
    css_files = tuple(
        entry["path"] for entry in data.get("preloadedCss", [])
    )

    return LibraryInfo(
        machine_name=data["machineName"],
        major_version=data["majorVersion"],
        minor_version=data["minorVersion"],
        runnable=bool(data.get("runnable", 0)),
        preloaded_js=js_files,
        preloaded_css=css_files,
    )


def read_semantics_json(
    vendor_dir: Path,
) -> List[Dict[str, Any]]:
    """Read ``semantics.json`` from a vendor directory.

    Parameters
    ----------
    vendor_dir:
        Path to the vendor directory containing ``semantics.json``.

    Returns
    -------
    list
        Parsed semantics fields, or an empty list if the file
        does not exist.
    """
    path = vendor_dir / "semantics.json"
    if not path.exists():
        return []
    return json.loads(path.read_text(encoding="utf-8"))
