"""Tenant management commands for Teams Phone CLI.

This module provides CLI commands for managing multi-tenant configurations,
including listing, adding, removing, switching, and testing tenant profiles.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Optional
from uuid import UUID

if TYPE_CHECKING:
    from teams_phone.infrastructure import OutputFormatter

import typer

from teams_phone.cli.context import get_context
from teams_phone.exceptions import TeamsPhoneError
from teams_phone.infrastructure import CacheManager
from teams_phone.models import AuthMethod, TenantProfile
from teams_phone.services import AuthService, TenantService

tenants_app = typer.Typer(
    name="tenants",
    help="Manage tenant profiles.",
    no_args_is_help=True,
)


def _create_tenant_service(ctx: typer.Context) -> tuple[TenantService, OutputFormatter]:
    """Create TenantService and return it with the formatter.

    Args:
        ctx: Typer context with CLIContext.

    Returns:
        Tuple of (TenantService, OutputFormatter).
    """
    cli_ctx = get_context(ctx)
    formatter = cli_ctx.get_output_formatter()
    config_manager = cli_ctx.get_config_manager()
    cache_manager = CacheManager()
    auth_service = AuthService(config_manager, cache_manager)
    tenant_service = TenantService(config_manager, auth_service)
    return tenant_service, formatter


@tenants_app.command("list")
def list_tenants(ctx: typer.Context) -> None:
    """List all configured tenant profiles."""
    cli_ctx = get_context(ctx)
    formatter = cli_ctx.get_output_formatter()

    try:
        tenant_service, _ = _create_tenant_service(ctx)
        tenants = tenant_service.list_tenants()

        # Get current tenant name for marking "Current" status
        try:
            current = tenant_service.get_current_tenant()
            current_name = current.name
        except TeamsPhoneError:
            current_name = None

        if cli_ctx.json_output:
            formatter.json(
                [
                    {
                        "name": t.name,
                        "display_name": t.display_name,
                        "tenant_id": str(t.tenant_id),
                        "auth_method": t.auth_method.value,
                        "is_current": t.name == current_name,
                    }
                    for t in tenants
                ]
            )
        else:
            if not tenants:
                formatter.info("No tenants configured")
                formatter.info("Add a tenant with: teams-phone tenants add")
            else:
                formatter.table(
                    data=[
                        {
                            "name": t.name,
                            "display_name": t.display_name,
                            "tenant_id": str(t.tenant_id),
                            "status": "Current" if t.name == current_name else "",
                        }
                        for t in tenants
                    ],
                    columns=["name", "display_name", "tenant_id", "status"],
                    title="Configured Tenants",
                )
    except TeamsPhoneError as e:
        formatter.error(e.message, remediation=e.remediation)
        raise typer.Exit(e.exit_code)


@tenants_app.command()
def current(ctx: typer.Context) -> None:
    """Show the currently active tenant."""
    cli_ctx = get_context(ctx)
    formatter = cli_ctx.get_output_formatter()

    try:
        tenant_service, _ = _create_tenant_service(ctx)
        tenant = tenant_service.get_current_tenant()

        if cli_ctx.json_output:
            formatter.json(
                {
                    "name": tenant.name,
                    "display_name": tenant.display_name,
                    "tenant_id": str(tenant.tenant_id),
                    "client_id": str(tenant.client_id),
                    "auth_method": tenant.auth_method.value,
                    "cert_path": tenant.cert_path,
                    "default_location": tenant.default_location,
                }
            )
        else:
            formatter.info(f"Current tenant: {tenant.display_name}")
            formatter.info(f"Profile name: {tenant.name}")
            formatter.info(f"Tenant ID: {tenant.tenant_id}")
            formatter.info(f"Client ID: {tenant.client_id}")
            formatter.info(f"Auth method: {tenant.auth_method.value}")
            if tenant.cert_path:
                formatter.info(f"Certificate: {tenant.cert_path}")
            if tenant.default_location:
                formatter.info(f"Default location: {tenant.default_location}")
    except TeamsPhoneError as e:
        formatter.error(e.message, remediation=e.remediation)
        raise typer.Exit(e.exit_code)


@tenants_app.command()
def switch(
    ctx: typer.Context,
    name: str = typer.Argument(..., help="Name of the tenant profile to switch to."),
    no_login: bool = typer.Option(
        False,
        "--no-login",
        help="Skip automatic login when switching.",
    ),
) -> None:
    """Switch to a different tenant profile."""
    cli_ctx = get_context(ctx)
    formatter = cli_ctx.get_output_formatter()

    try:
        tenant_service, _ = _create_tenant_service(ctx)
        tenant = tenant_service.switch_tenant(name, auto_login=not no_login)

        if cli_ctx.json_output:
            formatter.json(
                {
                    "status": "switched",
                    "name": tenant.name,
                    "display_name": tenant.display_name,
                    "tenant_id": str(tenant.tenant_id),
                }
            )
        else:
            formatter.success(f"Switched to tenant: {tenant.display_name}")
            formatter.info(f"Tenant ID: {tenant.tenant_id}")
    except TeamsPhoneError as e:
        formatter.error(e.message, remediation=e.remediation)
        raise typer.Exit(e.exit_code)


@tenants_app.command()
def test(
    ctx: typer.Context,
    name: Optional[str] = typer.Argument(
        None, help="Tenant profile name to test (default: current tenant)."
    ),
) -> None:
    """Test connection to a tenant."""
    cli_ctx = get_context(ctx)
    formatter = cli_ctx.get_output_formatter()

    try:
        tenant_service, _ = _create_tenant_service(ctx)

        # Use current tenant if name not provided
        if name is None:
            current = tenant_service.get_current_tenant()
            name = current.name

        result = tenant_service.test_connection(name)

        if cli_ctx.json_output:
            formatter.json(
                {
                    "success": result.success,
                    "tenant_name": result.tenant_name,
                    "latency_ms": result.latency_ms,
                    "permissions": result.permissions,
                    "error_message": result.error_message,
                }
            )
        else:
            if result.success:
                formatter.success(f"Connection to '{result.tenant_name}' successful")
                if result.latency_ms is not None:
                    formatter.info(f"Latency: {result.latency_ms}ms")
                if result.permissions:
                    formatter.info(f"Permissions: {len(result.permissions)} scopes")
            else:
                formatter.error(
                    f"Connection to '{result.tenant_name}' failed",
                    remediation=result.error_message,
                )
                raise typer.Exit(1)
    except TeamsPhoneError as e:
        formatter.error(e.message, remediation=e.remediation)
        raise typer.Exit(e.exit_code)


@tenants_app.command()
def remove(
    ctx: typer.Context,
    name: str = typer.Argument(..., help="Name of the tenant profile to remove."),
    force: bool = typer.Option(
        False,
        "--force",
        "-f",
        help="Skip confirmation prompt.",
    ),
) -> None:
    """Remove a tenant profile."""
    cli_ctx = get_context(ctx)
    formatter = cli_ctx.get_output_formatter()

    try:
        tenant_service, _ = _create_tenant_service(ctx)

        # Confirm removal unless --force is used
        if not force:
            confirm = typer.confirm(f"Are you sure you want to remove tenant '{name}'?")
            if not confirm:
                formatter.info("Removal cancelled")
                raise typer.Exit(0)

        tenant_service.remove_tenant(name)

        if cli_ctx.json_output:
            formatter.json(
                {
                    "status": "removed",
                    "name": name,
                }
            )
        else:
            formatter.success(f"Removed tenant: {name}")
    except TeamsPhoneError as e:
        formatter.error(e.message, remediation=e.remediation)
        raise typer.Exit(e.exit_code)


@tenants_app.command()
def add(
    ctx: typer.Context,
    name: str = typer.Argument(..., help="Profile name for the tenant."),
    tenant_id: str = typer.Argument(..., help="Microsoft Entra tenant ID (UUID)."),
    client_id: str = typer.Argument(..., help="App registration client ID (UUID)."),
    display_name: str = typer.Option(
        ...,
        "--display-name",
        "-d",
        help="Human-readable display name for the tenant.",
    ),
    auth_method: AuthMethod = typer.Option(
        AuthMethod.CERTIFICATE,
        "--auth-method",
        "-a",
        help="Authentication method.",
    ),
    cert_path: Optional[str] = typer.Option(
        None,
        "--cert-path",
        "-c",
        help="Path to certificate file (for certificate auth).",
    ),
    default_location: Optional[str] = typer.Option(
        None,
        "--default-location",
        "-l",
        help="Default emergency location for number assignments.",
    ),
) -> None:
    """Add a new tenant profile."""
    cli_ctx = get_context(ctx)
    formatter = cli_ctx.get_output_formatter()

    try:
        # Validate UUIDs
        try:
            validated_tenant_id = UUID(tenant_id)
        except ValueError:
            formatter.error(
                f"Invalid tenant ID: {tenant_id}",
                remediation="Tenant ID must be a valid UUID (e.g., xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).",
            )
            raise typer.Exit(5)  # ValidationError exit code

        try:
            validated_client_id = UUID(client_id)
        except ValueError:
            formatter.error(
                f"Invalid client ID: {client_id}",
                remediation="Client ID must be a valid UUID (e.g., xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).",
            )
            raise typer.Exit(5)  # ValidationError exit code

        # Create tenant profile
        profile = TenantProfile(
            name=name,
            tenant_id=validated_tenant_id,
            client_id=validated_client_id,
            display_name=display_name,
            auth_method=auth_method,
            cert_path=cert_path,
            default_location=default_location,
        )

        tenant_service, _ = _create_tenant_service(ctx)
        tenant_service.add_tenant(profile)

        if cli_ctx.json_output:
            formatter.json(
                {
                    "status": "added",
                    "name": profile.name,
                    "display_name": profile.display_name,
                    "tenant_id": str(profile.tenant_id),
                    "client_id": str(profile.client_id),
                    "auth_method": profile.auth_method.value,
                }
            )
        else:
            formatter.success(f"Added tenant: {profile.display_name}")
            formatter.info(f"Profile name: {profile.name}")
            formatter.info(f"Tenant ID: {profile.tenant_id}")
            formatter.info(f"Client ID: {profile.client_id}")
            formatter.info(f"Auth method: {profile.auth_method.value}")
            if profile.cert_path:
                formatter.info(f"Certificate: {profile.cert_path}")
    except TeamsPhoneError as e:
        formatter.error(e.message, remediation=e.remediation)
        raise typer.Exit(e.exit_code)
