"""
Device Pairing & Authentication.

Flow:
1. User runs `neura-runtime pair`
2. Runtime generates a 6-digit pairing code
3. User enters code in Neura web dashboard
4. Cloud sends device token via pairing WebSocket
5. Token stored in ~/.neura/device_token
6. All future tunnel connections use this token
"""
import asyncio
import json
import secrets
import string
from typing import Optional

import httpx

from .config import RuntimeConfig, save_device_token, get_device_token


def generate_pairing_code() -> str:
    """Generate a 6-digit alphanumeric pairing code."""
    chars = string.ascii_uppercase + string.digits
    # Remove ambiguous characters
    chars = chars.replace("O", "").replace("0", "").replace("I", "").replace("1", "")
    return "".join(secrets.choice(chars) for _ in range(6))


async def start_pairing(config: RuntimeConfig) -> Optional[str]:
    """
    Initiate device pairing with Neura Cloud.

    Returns the device token if pairing succeeds, None otherwise.
    """
    code = generate_pairing_code()
    print(f"\n  Pairing code: {code}\n")
    print(f"  Enter this code at {config.cloud_url}/settings/runtime\n")
    print("  Waiting for pairing...")

    # Register pairing code with cloud
    try:
        async with httpx.AsyncClient(timeout=10) as client:
            resp = await client.post(
                f"{config.cloud_url}/api/runtime/pair",
                json={
                    "pairing_code": code,
                    "device_name": config.device_name or _get_device_name(),
                },
            )

            if resp.status_code != 200:
                print(f"  Error: Could not register pairing code ({resp.status_code})")
                return None

            data = resp.json()
            session_id = data.get("session_id")

    except httpx.ConnectError:
        print(f"  Error: Could not connect to {config.cloud_url}")
        return None

    # Poll for completion (user enters code in dashboard)
    try:
        async with httpx.AsyncClient(timeout=5) as client:
            for _ in range(120):  # 2 minutes timeout
                await asyncio.sleep(1)
                resp = await client.get(
                    f"{config.cloud_url}/api/runtime/pair/{session_id}/status",
                )
                if resp.status_code == 200:
                    data = resp.json()
                    if data.get("status") == "paired":
                        token = data["device_token"]
                        save_device_token(token)

                        config.paired = True
                        config.device_id = data.get("device_id")
                        config.device_name = data.get("device_name", config.device_name)
                        config.save()

                        print("  Paired successfully!")
                        return token

    except Exception as e:
        print(f"  Pairing error: {e}")

    print("  Pairing timed out. Please try again.")
    return None


def is_paired() -> bool:
    """Check if this device is paired."""
    return get_device_token() is not None


def _get_device_name() -> str:
    """Generate a default device name."""
    import platform
    return f"{platform.node()}-{platform.system().lower()}"
