"""V14 pre-reservation, import, and service-lifecycle safety regressions."""

from __future__ import annotations

import hashlib
import json
import os
from pathlib import Path
from typing import final
from unittest.mock import patch

import pytest
from pydantic import JsonValue, TypeAdapter

import scripts.nutricoach_v150_sealed_controller as sealed_controller
from scripts.nutricoach_v150_concrete_host import ConcreteLiveHost
from scripts.nutricoach_v150_detached_bootstrap import (
    BootstrapDenied,
    verified_pythonpath,
)
from scripts.nutricoach_v150_host_operations import capacity_after, service_state
from scripts.nutricoach_v150_sealed_controller import (
    APPROVAL_PHRASE,
    DisposableService,
    SealedControllerError,
    execute_disposable,
)
from tests.test_nutricoach_v150_sealed_controller import target_fixture

_OBJECT = TypeAdapter(dict[str, JsonValue])


@final
class ObservedService:
    def __init__(self, *, sticky_stop: bool = False) -> None:
        self.running = True
        self.sticky_stop = sticky_stop

    def stop(self) -> None:
        if not self.sticky_stop:
            self.running = False

    def reload(self) -> None:
        return None

    def start(self) -> None:
        self.running = True

    def observe(self) -> dict[str, str]:
        return {
            "ActiveState": "active" if self.running else "inactive",
            "SubState": "running" if self.running else "dead",
            "MainPID": "401" if self.running else "0",
            "ExecStart": "/observed/runtime/bin/python -m gateway.run",
            "ExecMainStartTimestampMonotonic": "700",
        }


def test_detached_bootstrap_verifies_wheels_before_source(tmp_path: Path) -> None:
    wheels: list[dict[str, str]] = []
    for name in ("hermes.whl", "profile.whl"):
        path = tmp_path / name
        _ = path.write_bytes(name.encode())
        path.chmod(0o444)
        wheels.append({
            "path": str(path),
            "sha256": hashlib.sha256(path.read_bytes()).hexdigest(),
        })
    target = tmp_path / "sealed-target.json"
    _ = target.write_text(json.dumps({"wheels": wheels}) + "\n")
    source = tmp_path / "source"

    pythonpath = verified_pythonpath(target, source)

    assert pythonpath.split(os.pathsep) == [
        str(tmp_path / "hermes.whl"),
        str(tmp_path / "profile.whl"),
        str(source),
    ]
    hermes = tmp_path / "hermes.whl"
    hermes.chmod(0o644)
    _ = hermes.write_bytes(b"tampered")
    hermes.chmod(0o444)
    with pytest.raises(BootstrapDenied, match="wheel_integrity"):
        _ = verified_pythonpath(target, source)


def test_expired_weekly_authority_is_denied_before_ledger_reservation(
    tmp_path: Path,
) -> None:
    _ = target_fixture(tmp_path)
    host = ConcreteLiveHost.disposable(tmp_path, DisposableService())

    with (
        patch.object(
            sealed_controller,
            "WEEKLY_AUTHORITY_EXPIRES_AT",
            "2020-01-01T00:00:00+00:00",
        ),
        pytest.raises(SealedControllerError, match="weekly_authority_window"),
    ):
        _ = execute_disposable(APPROVAL_PHRASE, tmp_path, host)

    assert not host.ledger_reserved()
    assert not host.ledger_consumed()


def test_service_state_preserves_manager_observed_exec_start(
    tmp_path: Path,
) -> None:
    _ = target_fixture(tmp_path)
    host = ConcreteLiveHost.disposable(tmp_path, DisposableService())

    state = service_state(ObservedService(), host.paths)

    assert state["ExecStart"] == "/observed/runtime/bin/python -m gateway.run"


def test_host_stop_denies_service_that_remains_running(tmp_path: Path) -> None:
    _ = target_fixture(tmp_path)
    disposable = ConcreteLiveHost.disposable(tmp_path, DisposableService())
    host = ConcreteLiveHost(
        disposable.paths,
        ObservedService(sticky_stop=True),
        live=False,
    )

    with pytest.raises(RuntimeError, match="service_stop"):
        host.stop()


def test_capacity_postimage_uses_explicit_sealed_candidate(tmp_path: Path) -> None:
    candidate = "b" * 64
    registry = tmp_path / "registry.json"
    _ = registry.write_text(
        json.dumps({"version": 1, "owner": {}, "customers": []}) + "\n"
    )

    postimage = _OBJECT.validate_json(capacity_after(registry, candidate))
    policy = postimage["admission_policy"]

    assert isinstance(policy, dict)
    assert policy["candidate_digest"] == candidate


def test_live_host_loads_candidate_and_wheels_from_sealed_target(
    tmp_path: Path,
) -> None:
    candidate = "b" * 64
    hermes = tmp_path / "hermes.whl"
    profile = tmp_path / "profile.whl"
    _ = hermes.write_bytes(b"hermes")
    _ = profile.write_bytes(b"profile")
    target = tmp_path / "sealed-target.json"
    _ = target.write_text(
        json.dumps({
            "candidate_digest": candidate,
            "profile_root": str(tmp_path / "live-profile"),
            "unit": str(tmp_path / "gateway.service"),
            "dropin": str(tmp_path / "authority.conf"),
            "current_runtime": str(tmp_path / "current/venv"),
            "successor_runtime": str(tmp_path / "successor/venv"),
            "execution_root": str(tmp_path / "execution"),
            "global_approval_ledger": str(tmp_path / "ledger"),
            "protected_inventory": str(tmp_path / "inventory.json"),
            "wheels": [
                {
                    "path": str(hermes),
                    "sha256": hashlib.sha256(hermes.read_bytes()).hexdigest(),
                },
                {
                    "path": str(profile),
                    "sha256": hashlib.sha256(profile.read_bytes()).hexdigest(),
                },
            ],
        })
        + "\n"
    )

    host = ConcreteLiveHost.live_target(target)

    assert host.candidate_digest == candidate
    assert host.hermes_wheel == hermes
    assert host.profile_wheel == profile
    assert host.paths.registry == tmp_path / "live-profile/customers/registry.json"
