"""Tests for the session-hub stats, hosts, and delete-host CLI commands."""

import json
from datetime import UTC, datetime, timedelta
from unittest.mock import AsyncMock, MagicMock, patch

from typer.testing import CliRunner

from session_hub_cli.cli import app
from session_hub_core import HostInfo, HostStats, Stats, ToolStats

runner = CliRunner()

NOW = datetime(2026, 8, 1, 10, 0, 0, tzinfo=UTC)


def make_stats() -> Stats:
    return Stats(
        total_sessions=10,
        total_messages=50,
        by_host={"vps9": HostStats(sessions=8, messages=40, last_sync=NOW)},
        by_tool={"devin": ToolStats(sessions=8, messages=40)},
        oldest_session=NOW - timedelta(days=30),
        newest_session=NOW,
    )


def make_api() -> MagicMock:
    api = AsyncMock()
    api.close = AsyncMock()
    return api


@patch("session_hub_cli.commands.stats.get_query_api")
def test_stats_table(mock_get_api):
    api = make_api()
    api.get_stats.return_value = make_stats()
    mock_get_api.return_value = api

    result = runner.invoke(app, ["stats"])

    assert result.exit_code == 0
    assert "Total sessions" in result.stdout
    assert "10" in result.stdout
    assert "Total messages" in result.stdout
    assert "50" in result.stdout
    assert "vps9" in result.stdout
    assert "devin" in result.stdout
    assert "Date range" in result.stdout
    api.get_stats.assert_awaited_once()
    api.close.assert_awaited_once()


@patch("session_hub_cli.commands.stats.get_query_api")
def test_stats_json(mock_get_api):
    api = make_api()
    api.get_stats.return_value = make_stats()
    mock_get_api.return_value = api

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

    assert result.exit_code == 0
    data = json.loads(result.stdout)
    assert data["total_sessions"] == 10
    assert data["total_messages"] == 50
    assert data["by_host"]["vps9"]["sessions"] == 8
    assert data["by_tool"]["devin"]["messages"] == 40


@patch("session_hub_cli.commands.hosts.get_query_api")
def test_hosts_table(mock_get_api):
    api = make_api()
    api.get_hosts.return_value = [
        HostInfo(
            host="vps9",
            last_sync=datetime.now(UTC) - timedelta(hours=1),
            session_count=8,
            message_count=40,
        ),
        HostInfo(
            host="old-host",
            last_sync=datetime.now(UTC) - timedelta(hours=30),
            session_count=1,
            message_count=2,
        ),
        HostInfo(host="never-host", last_sync=None, session_count=0, message_count=0),
    ]
    mock_get_api.return_value = api

    result = runner.invoke(app, ["hosts"])

    assert result.exit_code == 0
    assert "vps9" in result.stdout
    assert "old-host" in result.stdout
    assert "never-host" in result.stdout
    assert "OK" in result.stdout
    assert "STALE (30h ago)" in result.stdout
    assert "NEVER" in result.stdout


@patch("session_hub_cli.commands.hosts.get_query_api")
def test_hosts_json(mock_get_api):
    api = make_api()
    api.get_hosts.return_value = [
        HostInfo(host="vps9", last_sync=NOW, session_count=8, message_count=40)
    ]
    mock_get_api.return_value = api

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

    assert result.exit_code == 0
    data = json.loads(result.stdout)
    assert isinstance(data, list)
    assert data[0]["host"] == "vps9"
    assert data[0]["session_count"] == 8


@patch("session_hub_cli.commands.delete_host.get_query_api")
def test_delete_host_with_confirmation(mock_get_api):
    api = make_api()
    api.delete_host_data.return_value = 8
    mock_get_api.return_value = api

    result = runner.invoke(app, ["delete-host", "vps9"], input="y\n")

    assert result.exit_code == 0
    assert "Deleted 8 sessions for host 'vps9'" in result.stdout
    api.delete_host_data.assert_awaited_once_with("vps9")


@patch("session_hub_cli.commands.delete_host.get_query_api")
def test_delete_host_aborted(mock_get_api):
    api = make_api()
    mock_get_api.return_value = api

    result = runner.invoke(app, ["delete-host", "vps9"], input="n\n")

    assert result.exit_code == 1
    api.delete_host_data.assert_not_awaited()


@patch("session_hub_cli.commands.delete_host.get_query_api")
def test_delete_host_force(mock_get_api):
    api = make_api()
    api.delete_host_data.return_value = 8
    mock_get_api.return_value = api

    result = runner.invoke(app, ["delete-host", "vps9", "--force"])

    assert result.exit_code == 0
    assert "Deleted 8 sessions for host 'vps9'" in result.stdout
    api.delete_host_data.assert_awaited_once_with("vps9")
