"""Tests for the SSH remote/bootstrap layer (the credential-free half of Pass 3)."""

from __future__ import annotations

import sys
from typing import TYPE_CHECKING

import pytest

from mgf.cloud import remote
from mgf.cloud.__main__ import main
from mgf.cloud.exceptions import ConfigError, OperationError
from mgf.cloud.remote import (
    FakeRemoteClient,
    RemoteHost,
    RemoteResult,
    deploy_compose_bundle,
    install_docker,
    run_commands,
)

if TYPE_CHECKING:
    from collections.abc import Callable
    from pathlib import Path


def _fake_connect(captured: dict[str, object]) -> Callable[..., FakeRemoteClient]:
    client = FakeRemoteClient()

    def connect(
        host: RemoteHost, *, accept_new: bool = False, timeout: float = 30.0
    ) -> FakeRemoteClient:
        captured["host"] = host
        captured["accept_new"] = accept_new
        captured["client"] = client
        return client

    return connect


# --- library layer -------------------------------------------------------
def test_remote_result_ok() -> None:
    assert RemoteResult(command="x", exit_status=0).ok
    assert not RemoteResult(command="x", exit_status=1).ok


def test_fake_client_records() -> None:
    client = FakeRemoteClient()
    assert client.exec("uptime").ok
    assert client.commands == ["uptime"]
    client.push_bytes(b"data", "/tmp/x")
    assert client.files["/tmp/x"] == b"data"
    client.close()
    assert client.closed


def test_run_commands_stops_on_failure() -> None:
    client = FakeRemoteClient(fail=("boom",))
    with pytest.raises(OperationError):
        run_commands(client, ["ok1", "boom-cmd", "never"])
    assert client.commands == ["ok1", "boom-cmd"]


def test_run_commands_sudo() -> None:
    client = FakeRemoteClient()
    run_commands(client, ["apt update"], sudo=True)
    assert client.commands == ["sudo apt update"]


def test_install_docker() -> None:
    client = FakeRemoteClient()
    results = install_docker(client)
    assert all(r.ok for r in results)
    assert any("get.docker.com" in cmd for cmd in client.commands)
    assert all(cmd.startswith("sudo ") for cmd in client.commands)


def test_deploy_compose_bundle() -> None:
    client = FakeRemoteClient()
    files = {"docker-compose.yml": b"services: {}", ".env": b"X=1"}
    deploy_compose_bundle(client, files, "/opt/wp")
    assert client.files["/opt/wp/docker-compose.yml"] == b"services: {}"
    assert client.files["/opt/wp/.env"] == b"X=1"
    assert any("docker compose up -d" in cmd for cmd in client.commands)


def test_deploy_compose_bundle_no_up() -> None:
    client = FakeRemoteClient()
    deploy_compose_bundle(client, {"a": b"b"}, "/d", up=False)
    assert not any("compose up" in cmd for cmd in client.commands)


def test_connect_without_paramiko_raises_configerror(monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setitem(sys.modules, "paramiko", None)
    with pytest.raises(ConfigError):
        remote.connect(RemoteHost(host="h"))


class _FakeSSH:
    def __init__(self) -> None:
        self.closed = False

    def load_system_host_keys(self) -> None: ...
    def set_missing_host_key_policy(self, policy: object) -> None: ...
    def connect(self, **_: object) -> None: ...
    def close(self) -> None:
        self.closed = True


def _fake_paramiko() -> object:
    import types

    mod = types.ModuleType("paramiko")
    mod.SSHClient = _FakeSSH  # type: ignore[attr-defined]
    mod.AutoAddPolicy = object  # type: ignore[attr-defined]
    mod.RejectPolicy = object  # type: ignore[attr-defined]
    return mod


def test_connect_and_close_emit_ssh_audit_records(
    monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture
) -> None:
    """SC-17: opening + closing an SSH session emit audit=true records carrying
    host/user but never a key."""
    monkeypatch.setitem(sys.modules, "paramiko", _fake_paramiko())
    with caplog.at_level("INFO", logger="mgf.cloud.remote"):
        client = remote.connect(RemoteHost(host="h1", user="ubuntu"))
        client.close()
    connect_rec = next(r for r in caplog.records if getattr(r, "operation", None) == "ssh.connect")
    assert connect_rec.audit is True and connect_rec.host == "h1" and connect_rec.user == "ubuntu"
    assert any(getattr(r, "operation", None) == "ssh.disconnect" for r in caplog.records)


# --- CLI layer -----------------------------------------------------------
def test_cli_remote_exec(monkeypatch: pytest.MonkeyPatch) -> None:
    captured: dict[str, object] = {}
    monkeypatch.setattr("mgf.cloud.remote.connect", _fake_connect(captured))
    assert main(["remote", "exec", "myhost", "uptime", "--user", "root", "--accept-new"]) == 0
    host = captured["host"]
    assert isinstance(host, RemoteHost)
    assert host.host == "myhost"
    assert host.user == "root"
    assert captured["accept_new"] is True
    assert isinstance(captured["client"], FakeRemoteClient)
    assert captured["client"].commands == ["uptime"]
    assert captured["client"].closed


def test_cli_remote_exec_sudo(monkeypatch: pytest.MonkeyPatch) -> None:
    captured: dict[str, object] = {}
    monkeypatch.setattr("mgf.cloud.remote.connect", _fake_connect(captured))
    main(["remote", "exec", "h", "systemctl restart x", "--sudo"])
    assert isinstance(captured["client"], FakeRemoteClient)
    assert captured["client"].commands == ["sudo systemctl restart x"]


def test_cli_remote_push(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    captured: dict[str, object] = {}
    monkeypatch.setattr("mgf.cloud.remote.connect", _fake_connect(captured))
    src = tmp_path / "f.txt"
    src.write_bytes(b"hello")
    assert main(["remote", "push", "h", str(src), "/tmp/f.txt"]) == 0
    assert isinstance(captured["client"], FakeRemoteClient)
    assert captured["client"].files["/tmp/f.txt"] == b"hello"


def test_cli_bootstrap(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    captured: dict[str, object] = {}
    monkeypatch.setattr("mgf.cloud.remote.connect", _fake_connect(captured))
    bundle = tmp_path / "bundle"
    bundle.mkdir()
    (bundle / "docker-compose.yml").write_bytes(b"services: {}")
    (bundle / ".env").write_bytes(b"X=1")
    rc = main(
        [
            "bootstrap",
            "h",
            "--docker",
            "--compose-dir",
            str(bundle),
            "--remote-dir",
            "/opt/wp",
            "--accept-new",
        ]
    )
    assert rc == 0
    client = captured["client"]
    assert isinstance(client, FakeRemoteClient)
    assert any("get.docker.com" in cmd for cmd in client.commands)
    assert any("docker compose up -d" in cmd for cmd in client.commands)
    assert client.files["/opt/wp/docker-compose.yml"] == b"services: {}"


def test_cli_bootstrap_dry_run(
    monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
) -> None:
    captured: dict[str, object] = {}
    monkeypatch.setattr("mgf.cloud.remote.connect", _fake_connect(captured))
    assert main(["bootstrap", "h", "--docker", "--dry-run"]) == 0
    assert "[dry-run]" in capsys.readouterr().out
    assert "client" not in captured  # connect was never called
