"""R71b maintenance confirmation postconditions."""

from __future__ import annotations

import hashlib
import json
from datetime import date, datetime
from pathlib import Path
from typing import final

from pydantic import JsonValue, TypeAdapter

from gateway.platforms.nutrition_weekly_maintenance_contract import (
    Topic59MaintenanceScopeV1,
    canonical_json,
)
from scripts.nutricoach_v150_r71b_cron_watch import CronJobsEvent
from scripts.nutricoach_v150_r71b_maintenance_confirmation import (
    MaintenanceConfirmation,
)
from scripts.nutricoach_v150_r71b_maintenance_host import (
    R71bMaintenanceFiles,
    R71bMaintenancePaths,
)
from scripts.nutricoach_v150_r71b_package import derive_r71b_package
from scripts.nutricoach_v150_sealed_target import DisposableService

_OBJECT = TypeAdapter(dict[str, JsonValue])


@final
class ReadyWatcher:
    """Fixed event fake because the confirmed event was subscribed before start."""

    def wait(self, *, timeout_seconds: int) -> CronJobsEvent:
        assert timeout_seconds == 120
        return CronJobsEvent("jobs.json", True)


def test_confirmation_requires_cron_ok_typed_output_audit_and_unchanged_ledger(
    tmp_path: Path,
) -> None:
    # Given
    scope = Topic59MaintenanceScopeV1(
        candidate_digest="1" * 64,
        config_digest="2" * 64,
        route_digest="3" * 64,
        customer_identity_digest="4" * 64,
        card_slot="5" * 64,
        kst_day=date(2026, 9, 1),
        not_before=datetime.fromisoformat("2026-09-01T16:00:00+09:00"),
        expires_at=datetime.fromisoformat("2026-09-01T16:10:00+09:00"),
    )
    binding: dict[str, JsonValue] = _OBJECT.validate_python({
        "schema": "nutricoach-v150-r71b-package-binding-inputs-v1",
        "product_generation": "r71",
        "package_namespace": "r71b-maintenance",
        "authority_id": "nutricoach-v150-v15-runtime-authority-r71b-maintenance",
        "paths": {"observer_root": "/tmp/observer-r71"},
        "candidate": {"candidate_digest": "1" * 64},
        "wheels": [], "controller": {"files": {}},
        "protected_inventory": {"explicit_maintenance_volatile_paths": []},
        "dependency_snapshot": {"dependency_snapshot_sha256": "6" * 64},
        "authority_baseline": {"candidate_digest": "7" * 64},
        "target_binding_base": {"profile_root": "/tmp/profile"},
        "service_preparation": {"ActiveState": "active"},
        "maintenance_scope": scope.model_dump(mode="json", by_alias=True),
        "maintenance_scope_path": "maintenance/maintenance-scope.json",
        "maintenance_scope_file_sha256": "8" * 64,
        "maintenance_scope_digest": "9" * 64,
        "no_send_oracle": {"schema": "nutricoach-r71b-no-send-oracle-v1"},
        "no_send_oracle_path": "maintenance/no-send-oracle.json",
        "no_send_oracle_file_sha256": "a" * 64,
        "diagnosed_blocker_evidence": [],
    })
    artifacts = derive_r71b_package(binding, scope)
    profile = tmp_path / "profile"
    cron = profile / "cron/jobs.json"
    cron.parent.mkdir(parents=True)
    job: dict[str, JsonValue] = {
        "id": "6e042d5dff68",
        "name": "NutriCoach schedule dispatcher",
        "schedule_display": "* * * * *",
        "inline_card": "nutrition-coaching-tick",
        "deliver": "local",
        "enabled": True,
        "state": "scheduled",
        "last_status": "ok",
        "last_error": None,
        "last_run_at": "2026-09-01T16:01:00+09:00",
    }
    _ = cron.write_text(json.dumps({"jobs": [job]}), encoding="utf-8")
    dropin = tmp_path / "gateway.conf"
    _ = dropin.write_text("[Service]\n", encoding="utf-8")
    service = DisposableService()
    service.stop()
    files = R71bMaintenanceFiles(
        R71bMaintenancePaths(profile, tmp_path / "successor/venv", cron, dropin),
        service,
        artifacts.authority_bytes,
    )
    files.arm()
    files.hold_path.unlink()
    audit_fields: dict[str, JsonValue] = {
        "schema": "nutricoach-topic59-maintenance-skip-audit-v1",
        "hold_id": artifacts.hold.hold_id,
        "hold_sha256": artifacts.hold_sha256,
        "authority_id": artifacts.authority.authority_id,
        "package_binding_digest": artifacts.package_binding_digest,
        "candidate_digest": scope.candidate_digest,
        "config_digest": scope.config_digest,
        "route_digest": scope.route_digest,
        "customer_identity_digest": scope.customer_identity_digest,
        "card_slot": scope.card_slot,
        "kst_day": scope.kst_day.isoformat(),
        "recorded_at": "2026-09-01T16:01:00+09:00",
        "terminal_state": "maintenance_skipped", "disposition": "noop_maintenance",
        "sent": False, "delivered": False, "message_id": None,
        "provider_receipt": None, "provider_calls": 0, "network_calls": 0,
    }
    audit_fields["row_digest"] = hashlib.sha256(canonical_json(audit_fields)).hexdigest()
    _ = files.audit_path.write_bytes(canonical_json(audit_fields) + b"\n")
    ledger = profile / "data/weekly-operations-topic59.jsonl"
    ledger.parent.mkdir(exist_ok=True)
    _ = ledger.write_bytes(b"historical sending rows\n")
    output = profile / "cron/output/6e042d5dff68/r71b.md"
    output.parent.mkdir(parents=True)
    _ = output.write_text("Status: maintenance no-op completed\n", encoding="utf-8")
    evidence = MaintenanceConfirmation(
        ledger_path=ledger,
        ledger_sha256=hashlib.sha256(ledger.read_bytes()).hexdigest(),
        output_path=output.parent,
        provider_calls=0,
        network_calls=0,
    )

    # When
    files.confirm(ReadyWatcher(), evidence)

    # A restart rechecks the durable receipt rather than fabricating a watched event.
    files.recover_confirmed(evidence)
    files.finalize()

    # Then
    assert files.audit_path.is_file()
    assert files.confirmation_path.is_file()
    assert files.credential_path.read_bytes() == artifacts.authority_bytes
    assert files.credential_path.stat().st_mode & 0o777 == 0o400
    assert (
        f"LoadCredential=nutricoach-topic59-maintenance-r71b.json:{files.credential_path}"
        in dropin.read_text(encoding="utf-8")
    )
