#!/usr/bin/env python3
"""Independent live-profile verification with all network creation denied."""

from __future__ import annotations

import contextlib
import hashlib
import importlib.util
import io
import json
import os
import socket
import sys
from pathlib import Path
from types import SimpleNamespace

ROOT = Path(__file__).resolve().parent
PROFILE = Path("/home/cube/.hermes/profiles/dualcoachtest")
SPEC = importlib.util.spec_from_file_location(
    "verified_network_probe_v3", ROOT / "network_probe_v3.py"
)
assert SPEC and SPEC.loader
m = importlib.util.module_from_spec(SPEC)
sys.modules[SPEC.name] = m
SPEC.loader.exec_module(m)


def digest(path: Path) -> str:
    return hashlib.sha256(path.read_bytes()).hexdigest()


class FakeBot:
    def __init__(self, token: str, username: str):
        self.bot_id = int(token.partition(":")[0])
        self.username = username
        self.calls: list[str] = []

    async def __aenter__(self):
        self.calls.append("enter")
        return self

    async def __aexit__(self, *_args):
        self.calls.append("exit")

    async def get_me(self):
        self.calls.append("get_me")
        return SimpleNamespace(id=self.bot_id, username=self.username)


def denied(*_args, **_kwargs):
    raise AssertionError("network access forbidden in independent verifier")


def main() -> int:
    binding = m.load_profile_binding(PROFILE)
    before_authority = m.authority_hashes(PROFILE)
    before_env = dict(os.environ)
    bots: list[FakeBot] = []

    def factory(token: str) -> FakeBot:
        bot = FakeBot(token, binding.username)
        bots.append(bot)
        return bot

    old_socket = socket.socket
    old_connection = socket.create_connection

    def local_only_socket(*args, **kwargs):
        family = args[0] if args else kwargs.get("family", socket.AF_INET)
        if family != socket.AF_UNIX:
            denied()
        return old_socket(*args, **kwargs)

    old_factory = getattr(m, "production_bot_factory")
    old_argv = sys.argv[:]
    output = io.StringIO()
    try:
        socket.socket = local_only_socket
        socket.create_connection = denied
        setattr(m, "production_bot_factory", factory)
        sys.argv = [
            str(ROOT / "network_probe_v3.py"),
            "--profile",
            str(PROFILE),
            "--timeout",
            "10",
        ]
        with contextlib.redirect_stdout(output):
            code = getattr(m, "main")()
    finally:
        socket.socket = old_socket
        socket.create_connection = old_connection
        setattr(m, "production_bot_factory", old_factory)
        sys.argv = old_argv
    if code != 0:
        raise RuntimeError("offline main-path verification failed")
    document = json.loads(output.getvalue())
    if document.get("status") != "READY_TELEGRAM_TRANSPORT":
        raise RuntimeError("offline main path did not produce readiness")
    if len(bots) != 1 or bots[0].calls != ["enter", "get_me", "exit"]:
        raise RuntimeError("probe called an unexpected bot method")
    if binding.token in output.getvalue():
        raise RuntimeError("token leaked to output")
    if dict(os.environ) != before_env:
        raise RuntimeError("probe mutated process environment")
    after_authority = m.authority_hashes(PROFILE)
    if before_authority != after_authority:
        raise RuntimeError("live authority changed")
    proof = {
        "schema": "task26-network-probe-v3-independent-proof",
        "status": "PASS_INDEPENDENT_NO_NETWORK",
        "network_denied": True,
        "profile": str(binding.profile),
        "config_sha256": binding.config_sha256,
        "env_sha256": binding.env_sha256,
        "configured_username": binding.username,
        "bot_id_bound_from_token_prefix": True,
        "token_printed": False,
        "environment_unchanged": True,
        "bot_calls": bots[0].calls,
        "authority_sha256": after_authority,
        "probe_sha256": digest(ROOT / "network_probe_v3.py"),
    }
    target = ROOT / "independent-proof.json"
    fd = os.open(target, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
    os.write(
        fd, (json.dumps(proof, sort_keys=True, separators=(",", ":")) + "\n").encode()
    )
    os.fsync(fd)
    os.close(fd)
    print(json.dumps(proof, sort_keys=True))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
