"""Unit tests for CLI tenants commands."""

from __future__ import annotations

import json
from typing import TYPE_CHECKING
from unittest.mock import MagicMock, patch
from uuid import UUID

import pytest
from tests.conftest import CliRunner

from teams_phone.cli.main import app
from teams_phone.exceptions import ConfigurationError, NotFoundError, ValidationError
from teams_phone.models import AuthMethod, ConnectionTestResult, TenantProfile

if TYPE_CHECKING:
    pass

runner = CliRunner()


# Test fixtures
def _make_tenant(
    name: str = "test-tenant",
    display_name: str = "Test Tenant",
    tenant_id: str = "11111111-1111-1111-1111-111111111111",
    client_id: str = "22222222-2222-2222-2222-222222222222",
) -> TenantProfile:
    """Create a TenantProfile for testing."""
    return TenantProfile(
        name=name,
        display_name=display_name,
        tenant_id=UUID(tenant_id),
        client_id=UUID(client_id),
        auth_method=AuthMethod.CERTIFICATE,
        cert_path="/path/to/cert.pem",
    )


class TestTenantsListCommand:
    """Tests for tenants list command."""

    @pytest.mark.unit
    def test_list_shows_in_help(self) -> None:
        """list command appears in tenants help."""
        result = runner.invoke(app, ["tenants", "--help"])
        assert result.exit_code == 0
        assert "list" in result.stdout

    @pytest.mark.unit
    def test_list_empty(self) -> None:
        """list shows empty message when no tenants configured."""
        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.list_tenants.return_value = []
            mock_service.get_current_tenant.side_effect = ConfigurationError(
                "No default tenant"
            )
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["tenants", "list"])
            assert result.exit_code == 0
            assert "No tenants configured" in result.stdout

    @pytest.mark.unit
    def test_list_shows_tenants(self) -> None:
        """list shows configured tenants in table format."""
        tenants = [
            _make_tenant("contoso", "Contoso Ltd"),
            _make_tenant("fabrikam", "Fabrikam Inc"),
        ]
        current = tenants[0]

        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.list_tenants.return_value = tenants
            mock_service.get_current_tenant.return_value = current
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["tenants", "list"])
            assert result.exit_code == 0
            assert "contoso" in result.stdout
            assert "Contoso Ltd" in result.stdout
            assert "fabrikam" in result.stdout
            assert "Fabrikam Inc" in result.stdout

    @pytest.mark.unit
    def test_list_marks_current_tenant(self) -> None:
        """list marks the current tenant with status indicator."""
        tenants = [
            _make_tenant("contoso", "Contoso Ltd"),
            _make_tenant("fabrikam", "Fabrikam Inc"),
        ]
        current = tenants[0]

        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.list_tenants.return_value = tenants
            mock_service.get_current_tenant.return_value = current
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["tenants", "list"])
            assert result.exit_code == 0
            assert "Current" in result.stdout

    @pytest.mark.unit
    def test_list_json_output(self) -> None:
        """list outputs valid JSON with --json flag."""
        tenants = [_make_tenant()]
        current = tenants[0]

        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.list_tenants.return_value = tenants
            mock_service.get_current_tenant.return_value = current
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["--json", "tenants", "list"])
            assert result.exit_code == 0
            data = json.loads(result.stdout)
            assert len(data) == 1
            assert data[0]["name"] == "test-tenant"
            assert data[0]["display_name"] == "Test Tenant"
            assert data[0]["is_current"] is True

    @pytest.mark.unit
    def test_list_json_empty(self) -> None:
        """list outputs empty JSON array when no tenants."""
        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.list_tenants.return_value = []
            mock_service.get_current_tenant.side_effect = ConfigurationError(
                "No default tenant"
            )
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["--json", "tenants", "list"])
            assert result.exit_code == 0
            data = json.loads(result.stdout)
            assert data == []


class TestTenantsCurrentCommand:
    """Tests for tenants current command."""

    @pytest.mark.unit
    def test_current_shows_in_help(self) -> None:
        """current command appears in tenants help."""
        result = runner.invoke(app, ["tenants", "--help"])
        assert result.exit_code == 0
        assert "current" in result.stdout

    @pytest.mark.unit
    def test_current_shows_tenant(self) -> None:
        """current shows the active tenant."""
        tenant = _make_tenant()

        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.get_current_tenant.return_value = tenant
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["tenants", "current"])
            assert result.exit_code == 0
            assert "Test Tenant" in result.stdout
            assert "test-tenant" in result.stdout
            assert "11111111-1111-1111-1111-111111111111" in result.stdout

    @pytest.mark.unit
    def test_current_no_default_tenant(self) -> None:
        """current exits with error when no default tenant."""
        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.get_current_tenant.side_effect = ConfigurationError(
                "No default tenant configured",
                remediation="Set a default tenant with 'teams-phone tenants switch'",
            )
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["tenants", "current"])
            assert result.exit_code == 7  # ConfigurationError exit code

    @pytest.mark.unit
    def test_current_json_output(self) -> None:
        """current outputs valid JSON with --json flag."""
        tenant = _make_tenant()

        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.get_current_tenant.return_value = tenant
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["--json", "tenants", "current"])
            assert result.exit_code == 0
            data = json.loads(result.stdout)
            assert data["name"] == "test-tenant"
            assert data["display_name"] == "Test Tenant"
            assert data["tenant_id"] == "11111111-1111-1111-1111-111111111111"
            assert data["client_id"] == "22222222-2222-2222-2222-222222222222"
            assert data["auth_method"] == "certificate"


class TestTenantsSwitchCommand:
    """Tests for tenants switch command."""

    @pytest.mark.unit
    def test_switch_shows_in_help(self) -> None:
        """switch command appears in tenants help."""
        result = runner.invoke(app, ["tenants", "--help"])
        assert result.exit_code == 0
        assert "switch" in result.stdout

    @pytest.mark.unit
    def test_switch_requires_name(self) -> None:
        """switch requires tenant name argument."""
        result = runner.invoke(app, ["tenants", "switch"])
        assert result.exit_code == 2
        # Typer outputs error to stderr, combined output is in result.output
        output = result.stdout + (result.stderr or "")
        assert "NAME" in output or "Missing argument" in output or result.exit_code == 2

    @pytest.mark.unit
    def test_switch_success(self) -> None:
        """switch changes the active tenant."""
        tenant = _make_tenant("contoso", "Contoso Ltd")

        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.switch_tenant.return_value = tenant
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["tenants", "switch", "contoso"])
            assert result.exit_code == 0
            assert "Switched to tenant" in result.stdout
            assert "Contoso Ltd" in result.stdout
            mock_service.switch_tenant.assert_called_once_with(
                "contoso", auto_login=True
            )

    @pytest.mark.unit
    def test_switch_no_login_flag(self) -> None:
        """switch --no-login skips automatic login."""
        tenant = _make_tenant()

        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.switch_tenant.return_value = tenant
            mock_service_class.return_value = mock_service

            result = runner.invoke(
                app, ["tenants", "switch", "test-tenant", "--no-login"]
            )
            assert result.exit_code == 0
            mock_service.switch_tenant.assert_called_once_with(
                "test-tenant", auto_login=False
            )

    @pytest.mark.unit
    def test_switch_not_found(self) -> None:
        """switch exits with error when tenant not found."""
        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.switch_tenant.side_effect = NotFoundError(
                "Tenant 'nonexistent' not found",
                remediation="Use 'teams-phone tenants list' to see available tenants",
            )
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["tenants", "switch", "nonexistent"])
            assert result.exit_code == 4  # NotFoundError exit code

    @pytest.mark.unit
    def test_switch_json_output(self) -> None:
        """switch outputs valid JSON with --json flag."""
        tenant = _make_tenant()

        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.switch_tenant.return_value = tenant
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["--json", "tenants", "switch", "test-tenant"])
            assert result.exit_code == 0
            data = json.loads(result.stdout)
            assert data["status"] == "switched"
            assert data["name"] == "test-tenant"


class TestTenantsTestCommand:
    """Tests for tenants test command."""

    @pytest.mark.unit
    def test_test_shows_in_help(self) -> None:
        """test command appears in tenants help."""
        result = runner.invoke(app, ["tenants", "--help"])
        assert result.exit_code == 0
        assert "test" in result.stdout

    @pytest.mark.unit
    def test_test_uses_current_tenant(self) -> None:
        """test uses current tenant when no name provided."""
        current = _make_tenant()
        test_result = ConnectionTestResult(
            success=True,
            tenant_name="test-tenant",
            latency_ms=150,
            permissions=["https://graph.microsoft.com/.default"],
        )

        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.get_current_tenant.return_value = current
            mock_service.test_connection.return_value = test_result
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["tenants", "test"])
            assert result.exit_code == 0
            assert "successful" in result.stdout.lower()
            mock_service.test_connection.assert_called_once_with("test-tenant")

    @pytest.mark.unit
    def test_test_with_name(self) -> None:
        """test uses provided tenant name."""
        test_result = ConnectionTestResult(
            success=True,
            tenant_name="contoso",
            latency_ms=200,
            permissions=["https://graph.microsoft.com/.default"],
        )

        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.test_connection.return_value = test_result
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["tenants", "test", "contoso"])
            assert result.exit_code == 0
            assert "successful" in result.stdout.lower()
            mock_service.test_connection.assert_called_once_with("contoso")

    @pytest.mark.unit
    def test_test_failure(self) -> None:
        """test shows error message on connection failure."""
        test_result = ConnectionTestResult(
            success=False,
            tenant_name="contoso",
            latency_ms=None,
            error_message="Certificate not found",
        )

        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.test_connection.return_value = test_result
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["tenants", "test", "contoso"])
            assert result.exit_code == 1
            assert "failed" in result.stdout.lower()

    @pytest.mark.unit
    def test_test_json_output_success(self) -> None:
        """test outputs valid JSON with --json flag on success."""
        current = _make_tenant()
        test_result = ConnectionTestResult(
            success=True,
            tenant_name="test-tenant",
            latency_ms=150,
            permissions=["https://graph.microsoft.com/.default"],
        )

        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.get_current_tenant.return_value = current
            mock_service.test_connection.return_value = test_result
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["--json", "tenants", "test"])
            assert result.exit_code == 0
            data = json.loads(result.stdout)
            assert data["success"] is True
            assert data["tenant_name"] == "test-tenant"
            assert data["latency_ms"] == 150

    @pytest.mark.unit
    def test_test_json_output_failure(self) -> None:
        """test outputs valid JSON with --json flag on failure."""
        current = _make_tenant()
        test_result = ConnectionTestResult(
            success=False,
            tenant_name="test-tenant",
            error_message="Authentication failed",
        )

        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.get_current_tenant.return_value = current
            mock_service.test_connection.return_value = test_result
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["--json", "tenants", "test"])
            # JSON mode should still work even on failure (test_connection never raises)
            assert result.exit_code == 0
            data = json.loads(result.stdout)
            assert data["success"] is False
            assert data["error_message"] == "Authentication failed"


class TestTenantsRemoveCommand:
    """Tests for tenants remove command."""

    @pytest.mark.unit
    def test_remove_shows_in_help(self) -> None:
        """remove command appears in tenants help."""
        result = runner.invoke(app, ["tenants", "--help"])
        assert result.exit_code == 0
        assert "remove" in result.stdout

    @pytest.mark.unit
    def test_remove_requires_name(self) -> None:
        """remove requires tenant name argument."""
        result = runner.invoke(app, ["tenants", "remove"])
        assert result.exit_code == 2
        # Typer outputs error to stderr, combined output is in result.output
        output = result.stdout + (result.stderr or "")
        assert "NAME" in output or "Missing argument" in output or result.exit_code == 2

    @pytest.mark.unit
    def test_remove_confirms_by_default(self) -> None:
        """remove prompts for confirmation by default."""
        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service_class.return_value = mock_service

            # Answer 'n' to confirmation prompt
            result = runner.invoke(app, ["tenants", "remove", "contoso"], input="n\n")
            assert result.exit_code == 0
            assert "cancelled" in result.stdout.lower()
            mock_service.remove_tenant.assert_not_called()

    @pytest.mark.unit
    def test_remove_confirmed(self) -> None:
        """remove proceeds when user confirms."""
        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["tenants", "remove", "contoso"], input="y\n")
            assert result.exit_code == 0
            assert "Removed tenant" in result.stdout
            mock_service.remove_tenant.assert_called_once_with("contoso")

    @pytest.mark.unit
    def test_remove_force_flag(self) -> None:
        """remove --force skips confirmation."""
        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["tenants", "remove", "contoso", "--force"])
            assert result.exit_code == 0
            assert "Removed tenant" in result.stdout
            mock_service.remove_tenant.assert_called_once_with("contoso")

    @pytest.mark.unit
    def test_remove_not_found(self) -> None:
        """remove exits with error when tenant not found."""
        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.remove_tenant.side_effect = NotFoundError(
                "Tenant 'nonexistent' not found",
                remediation="Use 'teams-phone tenants list' to see available tenants",
            )
            mock_service_class.return_value = mock_service

            result = runner.invoke(app, ["tenants", "remove", "nonexistent", "--force"])
            assert result.exit_code == 4  # NotFoundError exit code

    @pytest.mark.unit
    def test_remove_json_output(self) -> None:
        """remove outputs valid JSON with --json flag."""
        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service_class.return_value = mock_service

            result = runner.invoke(
                app, ["--json", "tenants", "remove", "contoso", "--force"]
            )
            assert result.exit_code == 0
            data = json.loads(result.stdout)
            assert data["status"] == "removed"
            assert data["name"] == "contoso"


class TestTenantsAddCommand:
    """Tests for tenants add command."""

    @pytest.mark.unit
    def test_add_shows_in_help(self) -> None:
        """add command appears in tenants help."""
        result = runner.invoke(app, ["tenants", "--help"])
        assert result.exit_code == 0
        assert "add" in result.stdout

    @pytest.mark.unit
    def test_add_requires_arguments(self) -> None:
        """add requires name, tenant_id, and client_id arguments."""
        result = runner.invoke(app, ["tenants", "add"])
        assert result.exit_code == 2
        # Typer outputs error to stderr, combined output is in result.output
        output = result.stdout + (result.stderr or "")
        assert "Missing argument" in output or "NAME" in output or result.exit_code == 2

    @pytest.mark.unit
    def test_add_requires_display_name(self) -> None:
        """add requires --display-name option."""
        result = runner.invoke(
            app,
            [
                "tenants",
                "add",
                "test",
                "11111111-1111-1111-1111-111111111111",
                "22222222-2222-2222-2222-222222222222",
            ],
        )
        assert result.exit_code == 2
        # Typer outputs error to stderr, combined output is in result.output
        output = (result.stdout + (result.stderr or "")).lower()
        assert (
            "display-name" in output
            or "display_name" in output
            or result.exit_code == 2
        )

    @pytest.mark.unit
    def test_add_success(self) -> None:
        """add creates a new tenant profile."""
        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.add_tenant.return_value = _make_tenant()
            mock_service_class.return_value = mock_service

            result = runner.invoke(
                app,
                [
                    "tenants",
                    "add",
                    "test-tenant",
                    "11111111-1111-1111-1111-111111111111",
                    "22222222-2222-2222-2222-222222222222",
                    "--display-name",
                    "Test Tenant",
                ],
            )
            assert result.exit_code == 0
            assert "Added tenant" in result.stdout
            mock_service.add_tenant.assert_called_once()

    @pytest.mark.unit
    def test_add_with_all_options(self) -> None:
        """add with all options creates properly configured profile."""
        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.add_tenant.return_value = _make_tenant()
            mock_service_class.return_value = mock_service

            result = runner.invoke(
                app,
                [
                    "tenants",
                    "add",
                    "test-tenant",
                    "11111111-1111-1111-1111-111111111111",
                    "22222222-2222-2222-2222-222222222222",
                    "--display-name",
                    "Test Tenant",
                    "--auth-method",
                    "certificate",
                    "--cert-path",
                    "/path/to/cert.pem",
                    "--default-location",
                    "Building A",
                ],
            )
            assert result.exit_code == 0

            # Verify profile was passed with correct values
            call_args = mock_service.add_tenant.call_args
            profile = call_args[0][0]
            assert profile.name == "test-tenant"
            assert str(profile.tenant_id) == "11111111-1111-1111-1111-111111111111"
            assert str(profile.client_id) == "22222222-2222-2222-2222-222222222222"
            assert profile.display_name == "Test Tenant"
            assert profile.auth_method == AuthMethod.CERTIFICATE
            assert profile.cert_path == "/path/to/cert.pem"
            assert profile.default_location == "Building A"

    @pytest.mark.unit
    def test_add_invalid_tenant_id(self) -> None:
        """add exits with validation error for invalid tenant ID."""
        result = runner.invoke(
            app,
            [
                "tenants",
                "add",
                "test",
                "not-a-uuid",
                "22222222-2222-2222-2222-222222222222",
                "--display-name",
                "Test",
            ],
        )
        assert result.exit_code == 5  # ValidationError exit code
        assert "Invalid tenant ID" in result.stdout

    @pytest.mark.unit
    def test_add_invalid_client_id(self) -> None:
        """add exits with validation error for invalid client ID."""
        result = runner.invoke(
            app,
            [
                "tenants",
                "add",
                "test",
                "11111111-1111-1111-1111-111111111111",
                "not-a-uuid",
                "--display-name",
                "Test",
            ],
        )
        assert result.exit_code == 5  # ValidationError exit code
        assert "Invalid client ID" in result.stdout

    @pytest.mark.unit
    def test_add_json_output(self) -> None:
        """add outputs valid JSON with --json flag."""
        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.add_tenant.return_value = _make_tenant()
            mock_service_class.return_value = mock_service

            result = runner.invoke(
                app,
                [
                    "--json",
                    "tenants",
                    "add",
                    "test-tenant",
                    "11111111-1111-1111-1111-111111111111",
                    "22222222-2222-2222-2222-222222222222",
                    "--display-name",
                    "Test Tenant",
                ],
            )
            assert result.exit_code == 0
            data = json.loads(result.stdout)
            assert data["status"] == "added"
            assert data["name"] == "test-tenant"
            assert data["display_name"] == "Test Tenant"

    @pytest.mark.unit
    def test_add_validation_error_from_service(self) -> None:
        """add handles validation error from service."""
        with (
            patch("teams_phone.cli.tenants.CacheManager"),
            patch("teams_phone.cli.tenants.TenantService") as mock_service_class,
        ):
            mock_service = MagicMock()
            mock_service.add_tenant.side_effect = ValidationError(
                "Tenant 'test' already exists",
                remediation="Choose a different name or remove the existing tenant",
            )
            mock_service_class.return_value = mock_service

            result = runner.invoke(
                app,
                [
                    "tenants",
                    "add",
                    "test",
                    "11111111-1111-1111-1111-111111111111",
                    "22222222-2222-2222-2222-222222222222",
                    "--display-name",
                    "Test",
                ],
            )
            assert result.exit_code == 5  # ValidationError exit code


class TestTenantsCommandIntegration:
    """Integration tests for tenants command group."""

    @pytest.mark.unit
    def test_tenants_commands_appear_in_help(self) -> None:
        """All tenants commands appear in tenants --help."""
        result = runner.invoke(app, ["tenants", "--help"])
        assert result.exit_code == 0
        assert "list" in result.stdout
        assert "current" in result.stdout
        assert "switch" in result.stdout
        assert "test" in result.stdout
        assert "remove" in result.stdout
        assert "add" in result.stdout

    @pytest.mark.unit
    def test_tenants_no_args_shows_help(self) -> None:
        """tenants with no args shows help (exit code 2)."""
        result = runner.invoke(app, ["tenants"])
        assert result.exit_code == 2
        assert "Usage:" in result.stdout

    @pytest.mark.unit
    def test_tenants_appears_in_main_help(self) -> None:
        """tenants command group appears in main help."""
        result = runner.invoke(app, ["--help"])
        assert result.exit_code == 0
        assert "tenants" in result.stdout
