"""Authentication commands for Teams Phone CLI.

This module provides CLI commands for authenticating with Microsoft Entra ID,
managing tokens, and checking authentication status.
"""

from __future__ import annotations

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.services import AuthService

auth_app = typer.Typer(
    name="auth",
    help="Authentication commands.",
    no_args_is_help=True,
)


@auth_app.command()
def status(ctx: typer.Context) -> None:
    """Show current authentication status."""
    cli_ctx = get_context(ctx)
    formatter = cli_ctx.get_output_formatter()

    try:
        config_manager = cli_ctx.get_config_manager()
        cache_manager = CacheManager()
        auth_service = AuthService(config_manager, cache_manager)

        tenant_name = cli_ctx.tenant
        auth_status = auth_service.get_status(tenant_name)

        if cli_ctx.json_output:
            formatter.json(auth_status.model_dump(mode="json"))
        else:
            formatter.info(f"Status: {auth_status.status.value}")
            if auth_status.tenant_name:
                formatter.info(f"Tenant: {auth_status.tenant_name}")
            if auth_status.tenant_id:
                formatter.info(f"Tenant ID: {auth_status.tenant_id}")
            if auth_status.expires_at:
                formatter.info(f"Expires at: {auth_status.expires_at.isoformat()}")
    except TeamsPhoneError as e:
        formatter.error(e.message, remediation=e.remediation)
        raise typer.Exit(e.exit_code)


@auth_app.command()
def login(
    ctx: typer.Context,
    force: bool = typer.Option(
        False,
        "--force",
        "-f",
        help="Force new authentication even if token exists.",
    ),
) -> None:
    """Authenticate with the current tenant."""
    cli_ctx = get_context(ctx)
    formatter = cli_ctx.get_output_formatter()

    try:
        config_manager = cli_ctx.get_config_manager()
        cache_manager = CacheManager()
        auth_service = AuthService(config_manager, cache_manager)

        tenant_name = cli_ctx.tenant
        token = auth_service.login(tenant_name, force=force)

        if cli_ctx.json_output:
            formatter.json(
                {
                    "status": "authenticated",
                    "tenant_id": token.tenant_id,
                    "expires_at": token.expires_at.isoformat(),
                }
            )
        else:
            formatter.success("Successfully authenticated")
            formatter.info(f"Tenant ID: {token.tenant_id}")
            formatter.info(f"Token expires at: {token.expires_at.isoformat()}")
    except TeamsPhoneError as e:
        formatter.error(e.message, remediation=e.remediation)
        raise typer.Exit(e.exit_code)


@auth_app.command()
def logout(
    ctx: typer.Context,
    all_tenants: bool = typer.Option(
        False,
        "--all",
        "-a",
        help="Clear tokens for all tenants.",
    ),
) -> None:
    """Clear cached authentication tokens."""
    cli_ctx = get_context(ctx)
    formatter = cli_ctx.get_output_formatter()

    try:
        config_manager = cli_ctx.get_config_manager()
        cache_manager = CacheManager()
        auth_service = AuthService(config_manager, cache_manager)

        tenant_name = cli_ctx.tenant
        auth_service.logout(tenant_name, all_tenants=all_tenants)

        if cli_ctx.json_output:
            if all_tenants:
                formatter.json({"status": "logged_out", "all_tenants": True})
            else:
                formatter.json({"status": "logged_out", "tenant": tenant_name})
        else:
            if all_tenants:
                formatter.success("Logged out from all tenants")
            else:
                tenant_display = tenant_name or "default tenant"
                formatter.success(f"Logged out from {tenant_display}")
    except TeamsPhoneError as e:
        formatter.error(e.message, remediation=e.remediation)
        raise typer.Exit(e.exit_code)


@auth_app.command()
def refresh(
    ctx: typer.Context,
    force: bool = typer.Option(
        False,
        "--force",
        "-f",
        help="Force refresh even if token is still valid.",
    ),
) -> None:
    """Refresh cached authentication tokens."""
    cli_ctx = get_context(ctx)
    formatter = cli_ctx.get_output_formatter()

    try:
        config_manager = cli_ctx.get_config_manager()
        cache_manager = CacheManager()
        auth_service = AuthService(config_manager, cache_manager)

        tenant_name = cli_ctx.tenant

        if force:
            token = auth_service.refresh_token(tenant_name)
        else:
            # Check if token needs refresh before doing it
            auth_status = auth_service.get_status(tenant_name)
            from teams_phone.models import AuthStatusType

            if auth_status.status == AuthStatusType.AUTHENTICATED:
                if cli_ctx.json_output:
                    formatter.json(
                        {
                            "status": "already_valid",
                            "tenant_id": auth_status.tenant_id,
                            "expires_at": auth_status.expires_at.isoformat()
                            if auth_status.expires_at
                            else None,
                        }
                    )
                else:
                    formatter.info("Token is still valid, no refresh needed")
                    formatter.info("Use --force to refresh anyway")
                return

            token = auth_service.refresh_token(tenant_name)

        if cli_ctx.json_output:
            formatter.json(
                {
                    "status": "refreshed",
                    "tenant_id": token.tenant_id,
                    "expires_at": token.expires_at.isoformat(),
                }
            )
        else:
            formatter.success("Token refreshed successfully")
            formatter.info(f"Tenant ID: {token.tenant_id}")
            formatter.info(f"Token expires at: {token.expires_at.isoformat()}")
    except TeamsPhoneError as e:
        formatter.error(e.message, remediation=e.remediation)
        raise typer.Exit(e.exit_code)
