"""Recompute candidate LOC claims from the shipped wheel bytes."""

from __future__ import annotations

from pathlib import Path
from zipfile import BadZipFile, ZipFile

from scripts.verify_nutricoach_v140_candidate_core import (
    CandidateContractError,
    JsonValue,
    path_beneath,
    require_int,
    require_list,
    require_object,
    require_string,
)

_NUTRITION_COACHING_MEMBER = "gateway/platforms/nutrition_coaching.py"


def pure_python_loc(source: bytes) -> int:
    """Count nonblank, non-comment physical Python lines."""
    try:
        text = source.decode("utf-8")
    except UnicodeDecodeError as error:
        raise CandidateContractError("LOC source is not UTF-8") from error
    return sum(
        bool(line.strip()) and not line.lstrip().startswith("#")
        for line in text.splitlines()
    )


def _wheel_member_loc(wheel: Path, member: str) -> int:
    try:
        with ZipFile(wheel) as archive:
            return pure_python_loc(archive.read(member))
    except (BadZipFile, KeyError) as error:
        raise CandidateContractError(
            f"LOC wheel member is unavailable: {member}"
        ) from error


def verify_loc_delta(
    root: Path,
    manifest: dict[str, JsonValue],
    receipt: dict[str, JsonValue],
) -> None:
    """Require the LOC receipt to equal independently measured wheel bytes."""
    baseline = require_object(
        manifest.get("baseline_wheels"), "baseline_wheels"
    )
    builds = require_list(manifest.get("builds"), "builds")
    if not builds:
        raise CandidateContractError("LOC candidate build is unavailable")
    first_build = require_object(builds[0], "builds[0]")
    baseline_wheel = path_beneath(
        root, baseline.get("hermes"), "baseline Hermes wheel"
    )
    candidate_wheel = path_beneath(
        root, first_build.get("hermes"), "candidate Hermes wheel"
    )
    member = require_string(
        receipt.get("nutrition_coaching_member"),
        "LOC nutrition_coaching_member",
    )
    if member != _NUTRITION_COACHING_MEMBER:
        raise CandidateContractError("LOC member binding is invalid")
    baseline_loc = _wheel_member_loc(baseline_wheel, member)
    candidate_loc = _wheel_member_loc(candidate_wheel, member)
    claimed_baseline = require_int(
        receipt.get("baseline_nutrition_coaching_pure_loc"),
        "LOC baseline_nutrition_coaching_pure_loc",
    )
    claimed_candidate = require_int(
        receipt.get("nutrition_coaching_pure_loc"),
        "LOC nutrition_coaching_pure_loc",
    )
    claimed_delta = require_int(
        receipt.get("nutrition_coaching_delta"),
        "LOC nutrition_coaching_delta",
    )
    if (
        claimed_baseline != baseline_loc
        or claimed_candidate != candidate_loc
        or claimed_delta != candidate_loc - baseline_loc
    ):
        raise CandidateContractError("LOC receipt does not match wheel bytes")
    if candidate_loc > baseline_loc:
        raise CandidateContractError("LOC baseline delta increased")
