from __future__ import annotations

import json
from pathlib import Path

from typer.testing import CliRunner

from autosana_cli.cli import app
from autosana_cli.models import DoctorCheck, DoctorReport, Platform
from autosana_cli.state import StateStore

runner = CliRunner()


class FakeProc:
    def __init__(self, pid: int):
        self.pid = pid

    def poll(self):
        return None

    def wait(self):
        return 0


def successful_report(platform: Platform) -> DoctorReport:
    return DoctorReport(platform=platform, checks=[DoctorCheck("ok", True, "ok")])


def test_up_detach_json(monkeypatch, tmp_path: Path) -> None:
    from autosana_cli.models import Device, InstalledApp

    fake_device = Device(platform=Platform.IOS, name="iPhone 16 Pro", udid="SIM-1")
    monkeypatch.setattr("autosana_cli.cli.doctor.run_preflight", lambda platform: successful_report(platform))
    # Mock the booted device list (new code path calls list_booted_ios_simulators directly)
    monkeypatch.setattr("autosana_cli.cli.devices.list_booted_ios_simulators", lambda: [fake_device])
    monkeypatch.setattr(
        "autosana_cli.cli.devices.list_installed_apps",
        lambda device: ([InstalledApp(bundle_id="com.test.app", name="TestApp")], True),
    )
    monkeypatch.setattr("autosana_cli.cli.appium.start_appium", lambda **_kwargs: FakeProc(1111))
    monkeypatch.setattr("autosana_cli.cli.appium.wait_for_appium_ready", lambda *_args, **_kwargs: None)
    monkeypatch.setattr("autosana_cli.cli.tunnel.ensure_cloudflared", lambda: tmp_path / "cloudflared")
    monkeypatch.setattr(
        "autosana_cli.cli.tunnel.start_tunnel",
        lambda **_kwargs: (FakeProc(2222), "https://abc.trycloudflare.com"),
    )

    result = runner.invoke(app, ["up", "--platform", "ios", "--detach", "--json"])

    assert result.exit_code == 0
    payload = json.loads(result.stdout)
    assert payload["status"] == "ready"
    assert payload["platform"] == "ios"
    assert payload["device_udid"] == "SIM-1"
    assert len(payload["installed_apps"]) == 1
    assert payload["installed_apps"][0]["bundle_id"] == "com.test.app"
    assert payload["app_detection"] == "ok"
    sessions = StateStore().load_sessions()
    assert len(sessions) == 1
    assert sessions[0].tunnel_pid == 2222


def test_status_json(monkeypatch) -> None:
    store = StateStore()
    store.save_sessions(
        [
            __import__("autosana_cli.models", fromlist=["Session", "Platform"]).Session(
                session_id="ios-4723-20260319T120000Z",
                platform=Platform.IOS,
                device_name="iPhone 16 Pro",
                device_udid="SIM-1",
                appium_port=4723,
                appium_pid=123,
                tunnel_url="https://abc.trycloudflare.com",
                tunnel_pid=456,
                aux_port=8100,
                appium_log_path="/tmp/appium.log",
                tunnel_log_path="/tmp/tunnel.log",
                project_root="/tmp/project",
                started_at="2026-03-19T12:00:00Z",
            )
        ]
    )
    monkeypatch.setattr("autosana_cli.cli.is_pid_running", lambda _pid: True)
    monkeypatch.setattr("autosana_cli.cli.appium.is_appium_ready", lambda _port: True)

    result = runner.invoke(app, ["status", "--json"])

    assert result.exit_code == 0
    payload = json.loads(result.stdout)
    assert payload["sessions"][0]["status"] == "ready"


def test_down_all(monkeypatch) -> None:
    store = StateStore()
    store.save_sessions(
        [
            __import__("autosana_cli.models", fromlist=["Session", "Platform"]).Session(
                session_id="ios-4723-20260319T120000Z",
                platform=Platform.IOS,
                device_name="iPhone 16 Pro",
                device_udid="SIM-1",
                appium_port=4723,
                appium_pid=123,
                tunnel_url="https://abc.trycloudflare.com",
                tunnel_pid=456,
                aux_port=8100,
                appium_log_path="/tmp/appium.log",
                tunnel_log_path="/tmp/tunnel.log",
                project_root="/tmp/project",
                started_at="2026-03-19T12:00:00Z",
            )
        ]
    )
    stopped: list[str] = []
    monkeypatch.setattr("autosana_cli.cli.stop_session", lambda session: stopped.append(session.session_id))

    result = runner.invoke(app, ["down", "--all"])

    assert result.exit_code == 0
    assert stopped == ["ios-4723-20260319T120000Z"]
    assert StateStore().load_sessions() == []


def test_doctor_failure_exits_nonzero(monkeypatch) -> None:
    monkeypatch.setattr(
        "autosana_cli.cli.doctor.run_preflight",
        lambda platform: DoctorReport(platform=platform, checks=[DoctorCheck("appium", False, "missing")]),
    )

    result = runner.invoke(app, ["doctor", "--platform", "ios"])

    assert result.exit_code == 1
    assert "missing" in result.stdout
