"""Authentication commands for manta-client CLI.

OAuth2 login flow (via shared auth service + token exchange):
1. CLI resolves auth service URL (from config or manta-api /providers)
2. CLI requests CLI authorization URL from auth service
3. Browser opens authorization URL → user completes Feishu login
4. Auth service stores authorization code in Redis, CLI polls to retrieve it
5. CLI exchanges code with target manta-api /auth/token-exchange
6. manta-api creates user + token, CLI saves tokens to config
"""

from __future__ import annotations

import asyncio
import time
from typing import Any

import httpx
import typer

from manta_client.config import config_manager, get_config, save_config
from manta_client.output import console, print_error, print_key_value, print_success

app = typer.Typer(help="Authentication management")


async def resolve_auth_url(api_url: str) -> str | None:
    """Auto-discover auth service URL from manta-api."""
    try:
        async with httpx.AsyncClient() as client:
            response = await client.get(f"{api_url}/api/v1/auth/providers")
            result = response.json()
            if result.get("code") == 200 and result.get("data", {}).get("auth_url"):
                return result["data"]["auth_url"].rstrip("/")
    except Exception as e:
        console.print(f"[yellow]Could not discover auth service from API: {e}[/yellow]")

    return None


async def get_cli_auth_url(auth_url: str, provider: str) -> dict[str, Any] | None:
    """Get CLI authorization URL and state from auth service."""
    endpoint = f"{auth_url}/api/v1/oauth2/{provider}/cli"

    try:
        async with httpx.AsyncClient() as client:
            response = await client.get(endpoint)
            result = response.json()

            if result.get("code") == 200:
                return result.get("data")
            else:
                console.print(f"[red]Error: {result.get('msg', 'Unknown error')}[/red]")
                return None
    except Exception as e:
        console.print(f"[red]Failed to get authorization URL: {e}[/red]")
        return None


async def poll_cli_auth_code(
    auth_url: str, provider: str, state: str, timeout: int = 300
) -> str | None:
    """Poll auth service for CLI authorization code.

    Returns:
        Authorization code string or None if failed/timed out
    """
    endpoint = f"{auth_url}/api/v1/oauth2/{provider}/cli/poll/{state}"
    start = time.time()

    async with httpx.AsyncClient() as client:
        while time.time() - start < timeout:
            try:
                response = await client.get(endpoint)
                result = response.json()

                if result.get("code") == 200 and result.get("data") is not None:
                    return result["data"].get("auth_code")
                elif result.get("code") != 200:
                    console.print(f"[red]Error: {result.get('msg', 'Unknown error')}[/red]")
                    return None

                # Not ready yet, wait and retry
                await asyncio.sleep(2)
            except Exception as e:
                console.print(f"[red]Poll error: {e}[/red]")
                return None

    console.print("[red]Authorization timed out[/red]")
    return None


async def exchange_token(api_url: str, auth_code: str) -> dict[str, Any] | None:
    """Exchange authorization code with manta-api for access tokens.

    Args:
        api_url: Target manta-api base URL
        auth_code: Authorization code from auth service

    Returns:
        Token data dict or None if failed
    """
    endpoint = f"{api_url}/api/v1/auth/token-exchange"
    try:
        async with httpx.AsyncClient(timeout=10) as client:
            response = await client.post(endpoint, json={"code": auth_code})
            result = response.json()

            if result.get("code") == 200 and result.get("data"):
                return result["data"]
            else:
                msg = result.get("msg", "Unknown error")
                console.print(f"[red]Token exchange failed: {msg}[/red]")
                return None
    except Exception as e:
        console.print(f"[red]Token exchange failed: {e}[/red]")
        return None


@app.command("login")
def login() -> None:
    """Login via Feishu OAuth2."""
    provider = "feishu"
    config = get_config()

    # Check if already logged in
    if config.access_token:
        console.print("[yellow]You are already logged in.[/yellow]")
        confirm = typer.confirm("Do you want to login again?", default=False)
        if not confirm:
            raise typer.Exit(0)

    console.print("[cyan]Starting OAuth2 login...[/cyan]")

    # Resolve auth service URL from manta-api
    auth_url = asyncio.run(resolve_auth_url(config.api_url))
    if not auth_url:
        print_error("Could not discover auth service URL from API.")
        raise typer.Exit(1)

    console.print(f"[dim]Using auth service: {auth_url}[/dim]")

    # Get CLI auth URL with state
    cli_data = asyncio.run(get_cli_auth_url(auth_url, provider))
    if not cli_data:
        raise typer.Exit(1)

    state = cli_data["state"]
    oauth2_url = cli_data["auth_url"]

    # Open browser
    console.print("[cyan]Opening browser for authorization...[/cyan]")
    import webbrowser

    webbrowser.open(oauth2_url)

    console.print("[dim]Waiting for authorization (polling)...[/dim]")

    # Poll for authorization code
    auth_code = asyncio.run(poll_cli_auth_code(auth_url, provider, state))
    if not auth_code:
        print_error("Login failed: Authorization timed out or was cancelled")
        raise typer.Exit(1)

    # Exchange code with target manta-api for tokens
    console.print("[dim]Exchanging authorization code for tokens...[/dim]")
    token_data = asyncio.run(exchange_token(config.api_url, auth_code))

    if token_data:
        # Save tokens to config
        config.access_token = token_data["access_token"]
        config.refresh_token = token_data.get("refresh_token", "")
        config.session_uuid = token_data.get("session_uuid", "")
        user_info = token_data.get("user", {})
        config.user_id = str(user_info.get("id", ""))
        config.username = user_info.get("username", "")
        save_config(config)

        print_success("Login successful!")
        if config.username:
            console.print(f"[dim]Logged in as: {config.username}[/dim]")
        console.print(f"[dim]Token saved to {config_manager.config_path}[/dim]")
    else:
        print_error("Login failed: Token exchange failed")
        raise typer.Exit(1)


@app.command("logout")
def logout() -> None:
    """Logout and clear saved credentials."""
    config = get_config()

    if not config.access_token:
        console.print("[yellow]You are not logged in.[/yellow]")
        raise typer.Exit(0)

    config_manager.clear_auth()
    print_success("Logged out successfully.")


@app.command("whoami")
def whoami(
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Show current user information."""
    config = get_config()

    if not config.access_token:
        console.print("[yellow]You are not logged in.[/yellow]")
        console.print("Use 'manta-client auth login' to login.")
        raise typer.Exit(1)

    # Try to fetch user info from API
    async def fetch_user_info():
        try:
            from manta_client.api.client import MantaClient

            client = MantaClient()
            return await client.get("/api/v1/sys/users/me")
        except Exception as e:
            return {"error": str(e)}

    user_info = asyncio.run(fetch_user_info())

    if "error" in user_info:
        # Show local config info if API fails
        data = {
            "username": config.username or "(not available)",
            "user_id": config.user_id or "(not available)",
            "api_url": config.api_url,
            "authenticated": bool(config.access_token),
        }
        console.print("[yellow]Could not fetch user info from API. Showing local config.[/yellow]")
    else:
        data = {
            "username": user_info.get("username", ""),
            "nickname": user_info.get("nickname", ""),
            "email": user_info.get("email", ""),
            "user_id": user_info.get("id", ""),
            "status": "active" if user_info.get("status") else "inactive",
            "api_url": config.api_url,
        }

    if json_output:
        from manta_client.output import print_json

        print_json(data)
    else:
        print_key_value(data, title="Current User")
        console.print()
