"""Tests for CLI commands (cli/accounts.py, cli/vms.py, cli/browser.py, cli/system.py)."""

from unittest.mock import MagicMock, patch

import pytest

from click.testing import CliRunner
from proxym.ctl import main


class TestCLIAccounts:
    """Tests for proxym accounts commands."""

    @patch("proxym.cli.accounts.make_client")
    def test_accounts_list_empty(self, mock_make_client):
        """proxym accounts list → empty table."""
        mock_client = MagicMock()
        mock_client.get.return_value.json.return_value = {"accounts": []}
        mock_make_client.return_value = mock_client

        runner = CliRunner()
        result = runner.invoke(main, ["accounts", "list"])

        assert result.exit_code == 0
        assert "No accounts" in result.output or "accounts" in result.output

    @patch("proxym.cli.accounts.make_client")
    def test_accounts_add_valid(self, mock_make_client):
        """proxym accounts add --provider anthropic --key sk-... → success."""
        mock_client = MagicMock()
        mock_client.post.return_value.json.return_value = {"id": "acc-123", "name": "Test"}
        mock_make_client.return_value = mock_client

        runner = CliRunner()
        result = runner.invoke(main, [
            "accounts", "add",
            "--name", "Test Account",
            "--provider", "anthropic",
            "--api-key", "sk-ant-test123",
        ])

        assert result.exit_code == 0
        mock_client.post.assert_called_once()

    @patch("proxym.cli.accounts.make_client")
    def test_accounts_add_invalid_provider(self, mock_make_client):
        """Unknown provider → readable error."""
        mock_client = MagicMock()
        mock_client.post.return_value.status_code = 400
        mock_client.post.return_value.json.return_value = {"detail": "Unknown provider"}
        mock_make_client.return_value = mock_client

        runner = CliRunner()
        result = runner.invoke(main, [
            "accounts", "add",
            "--name", "Test",
            "--provider", "invalid-provider",
            "--api-key", "sk-test",
        ])

        assert result.exit_code != 0 or "error" in result.output.lower()

    @patch("proxym.cli.accounts.make_client")
    def test_accounts_costs_shows_breakdown(self, mock_make_client):
        """proxym accounts costs shows cost breakdown."""
        mock_client = MagicMock()
        mock_client.get.return_value.json.return_value = {
            "summary": {"daily_total_usd": 1.23, "monthly_total_usd": 45.67},
            "accounts": [
                {"name": "Test", "daily_cost": 0.5, "monthly_cost": 10.0},
            ],
        }
        mock_make_client.return_value = mock_client

        runner = CliRunner()
        result = runner.invoke(main, ["accounts", "costs"])

        assert result.exit_code == 0


class TestCLIVMs:
    """Tests for proxym vm commands."""

    @patch("proxym.cli.vms.make_client")
    def test_vm_list_empty(self, mock_make_client):
        """proxym vm list with no VMs."""
        mock_client = MagicMock()
        mock_client.get.return_value.json.return_value = {"vms": []}
        mock_make_client.return_value = mock_client

        runner = CliRunner()
        result = runner.invoke(main, ["vm", "list"])

        assert result.exit_code == 0

    @patch("proxym.cli.vms.make_client")
    def test_vm_create_calls_correct_endpoint(self, mock_make_client):
        """proxym vm create calls correct endpoint."""
        mock_client = MagicMock()
        mock_client.post.return_value.json.return_value = {"id": "vm-123", "name": "test-vm"}
        mock_make_client.return_value = mock_client

        runner = CliRunner()
        result = runner.invoke(main, [
            "vm", "create",
            "--name", "test-vm",
            "--tool", "windsurf",
            "--account", "acc-123",
        ])

        assert result.exit_code == 0
        mock_client.post.assert_called_once()

    @patch("proxym.cli.vms.make_client")
    def test_vm_action_start(self, mock_make_client):
        """proxym vm start {vm_id}."""
        mock_client = MagicMock()
        mock_client.post.return_value.json.return_value = {"ok": True}
        mock_make_client.return_value = mock_client

        runner = CliRunner()
        result = runner.invoke(main, ["vm", "start", "vm-123"])

        assert result.exit_code == 0
        mock_client.post.assert_called_with("/dashboard/vms/vm-123/start", json={})

    @patch("proxym.cli.vms.make_client")
    def test_vm_action_stop(self, mock_make_client):
        """proxym vm stop {vm_id}."""
        mock_client = MagicMock()
        mock_client.post.return_value.json.return_value = {"ok": True}
        mock_make_client.return_value = mock_client

        runner = CliRunner()
        result = runner.invoke(main, ["vm", "stop", "vm-123"])

        assert result.exit_code == 0
        mock_client.post.assert_called_with("/dashboard/vms/vm-123/stop", params={"force": False}, json={})

    @patch("proxym.cli.vms.make_client")
    def test_vm_action_invalid(self, mock_make_client):
        """proxym vm action nonexistent start → 404."""
        mock_client = MagicMock()
        mock_client.post.return_value.status_code = 404
        mock_client.post.return_value.json.return_value = {"detail": "VM not found"}
        mock_make_client.return_value = mock_client

        runner = CliRunner()
        result = runner.invoke(main, ["vm", "start", "nonexistent"])

        assert result.exit_code != 0 or "not found" in result.output.lower()


class TestCLIBrowser:
    """Tests for proxym browser commands."""

    @patch("proxym.cli.browser.make_client")
    def test_browser_list_empty(self, mock_make_client):
        """proxym browser list with no profiles."""
        mock_client = MagicMock()
        mock_client.get.return_value.json.return_value = {"profiles": []}
        mock_make_client.return_value = mock_client

        runner = CliRunner()
        result = runner.invoke(main, ["browser", "list"])

        assert result.exit_code == 0

    @patch("proxym.cli.browser.make_client")
    def test_browser_assign_valid(self, mock_make_client):
        """proxym browser assign {profile} --account {id}."""
        mock_client = MagicMock()
        mock_client.post.return_value.json.return_value = {"ok": True}
        mock_make_client.return_value = mock_client

        runner = CliRunner()
        result = runner.invoke(main, ["browser", "assign", "work-profile", "--account", "acc-123"])

        assert result.exit_code == 0
        mock_client.post.assert_called_once()


class TestCLIDispatch:
    """Tests for CLI dispatch and top-level commands."""

    def test_main_no_args_shows_help(self):
        """proxym with no args shows help."""
        runner = CliRunner()
        result = runner.invoke(main, [])

        assert result.exit_code == 0
        assert "usage" in result.output.lower()

    def test_main_unknown_command_exits_nonzero(self):
        """proxym unknown-command exits with non-zero."""
        runner = CliRunner()
        result = runner.invoke(main, ["unknown-command"])

        assert result.exit_code != 0 or "invalid choice" in result.output.lower()

    @patch("proxym.cli.system.cmd_status")
    def test_dispatch_status(self, mock_status):
        """proxym status dispatches correctly."""
        runner = CliRunner()
        result = runner.invoke(main, ["status"])

        assert result.exit_code == 0
        mock_status.assert_called_once()

    @patch("proxym.cli.system.cmd_models")
    def test_dispatch_models(self, mock_models):
        """proxym models dispatches correctly."""
        runner = CliRunner()
        result = runner.invoke(main, ["models"])

        assert result.exit_code == 0
        mock_models.assert_called_once()
