"""
BLE CLI commands.
"""

from typing import Optional

import typer
from rich.console import Console

from airctl.cli.output import OutputFormatter

app = typer.Typer(help="Bluetooth Low Energy commands")
console = Console()


@app.command("scan")
def ble_scan(
    timeout: float = typer.Option(10.0, "--timeout", "-t", help="Scan timeout in seconds"),
    service_uuids: Optional[str] = typer.Option(
        None, "--service-uuids", help="Filter by service UUIDs (comma-separated)"
    ),
    name_filter: Optional[str] = typer.Option(None, "--name", "-n", help="Filter by exact device name"),
    human: bool = typer.Option(False, "-h", "--human", help="Human-readable output (default: JSON)"),
) -> None:
    """Scan for BLE devices."""
    formatter = OutputFormatter(json_output=not human)
    
    try:
        from airctl.daemon.auto_start import ensure_daemon_running
        from airctl.ipc.client import DaemonClient
        
        ensure_daemon_running()
        
        client = DaemonClient()
        uuids = service_uuids.split(",") if service_uuids else None
        
        result = client.scan(timeout=timeout, service_uuids=uuids)
        
        devices = result.get("devices", [])
        if name_filter:
            devices = [d for d in devices if d.get("name") == name_filter]
        
        formatter.print({"devices": devices, "count": len(devices)})
    except Exception as e:
        formatter.print_error(str(e))


@app.command("connect")
def ble_connect(
    address: str = typer.Argument(..., help="Device address or alias"),
    timeout: float = typer.Option(30.0, "--timeout", "-t", help="Connection timeout"),
    alias: Optional[str] = typer.Option(None, "-a", "--alias", help="Set device alias"),
    human: bool = typer.Option(False, "-h", "--human", help="Human-readable output (default: JSON)"),
) -> None:
    """Connect to a BLE device."""
    formatter = OutputFormatter(json_output=not human)
    
    try:
        from airctl.daemon.auto_start import ensure_daemon_running
        from airctl.ipc.client import DaemonClient
        
        ensure_daemon_running()
        
        client = DaemonClient()
        result = client.connect(address, timeout=timeout, alias=alias)
        formatter.print_success(f"Connected to {address}", result)
    except Exception as e:
        formatter.print_error(str(e))


@app.command("disconnect")
def ble_disconnect(
    address: str = typer.Argument(..., help="Device address or alias"),
    human: bool = typer.Option(False, "-h", "--human", help="Human-readable output (default: JSON)"),
) -> None:
    """Disconnect from a BLE device."""
    formatter = OutputFormatter(json_output=not human)
    
    try:
        from airctl.daemon.auto_start import ensure_daemon_running
        from airctl.ipc.client import DaemonClient
        
        ensure_daemon_running()
        
        client = DaemonClient()
        client.disconnect(address)
        formatter.print_success(f"Disconnected from {address}")
    except Exception as e:
        formatter.print_error(str(e))


@app.command("list")
def ble_list(
    human: bool = typer.Option(False, "-h", "--human", help="Human-readable output (default: JSON)"),
) -> None:
    """List connected devices."""
    formatter = OutputFormatter(json_output=not human)
    
    try:
        from airctl.daemon.auto_start import ensure_daemon_running
        from airctl.ipc.client import DaemonClient
        
        ensure_daemon_running()
        
        client = DaemonClient()
        result = client.list_devices()
        formatter.print(result)
    except Exception as e:
        formatter.print_error(str(e))


@app.command("services")
def ble_services(
    address: str = typer.Argument(..., help="Device address or alias"),
    human: bool = typer.Option(False, "-h", "--human", help="Human-readable output (default: JSON)"),
) -> None:
    """List GATT services of a connected device."""
    formatter = OutputFormatter(json_output=not human)
    
    try:
        from airctl.daemon.auto_start import ensure_daemon_running
        from airctl.ipc.client import DaemonClient
        
        ensure_daemon_running()
        
        client = DaemonClient()
        result = client.get_services(address)
        formatter.print(result)
    except Exception as e:
        formatter.print_error(str(e))


@app.command("characteristics")
def ble_characteristics(
    address: str = typer.Argument(..., help="Device address or alias"),
    service_uuid: Optional[str] = typer.Option(None, "--service", "-s", help="Filter by service UUID"),
    human: bool = typer.Option(False, "-h", "--human", help="Human-readable output (default: JSON)"),
) -> None:
    """List GATT characteristics of a connected device."""
    formatter = OutputFormatter(json_output=not human)
    
    try:
        from airctl.daemon.auto_start import ensure_daemon_running
        from airctl.ipc.client import DaemonClient
        
        ensure_daemon_running()
        
        client = DaemonClient()
        result = client.get_characteristics(address, service_uuid=service_uuid)
        formatter.print(result)
    except Exception as e:
        formatter.print_error(str(e))


@app.command("read")
def ble_read(
    address: str = typer.Argument(..., help="Device address or alias"),
    uuid: Optional[str] = typer.Option(None, "--uuid", "-u", help="Characteristic UUID"),
    handle: Optional[int] = typer.Option(None, "--handle", "-H", help="Characteristic handle (alternative to UUID)"),
    format: str = typer.Option("hex", "--format", "-f", help="Output format (hex/base64/text)"),
    human: bool = typer.Option(False, "-h", "--human", help="Human-readable output (default: JSON)"),
) -> None:
    """Read a characteristic value."""
    formatter = OutputFormatter(json_output=not human)
    
    if not uuid and not handle:
        formatter.print_error("Either --uuid or --handle must be specified")
        return
    
    try:
        from airctl.daemon.auto_start import ensure_daemon_running
        from airctl.ipc.client import DaemonClient
        
        ensure_daemon_running()
        
        client = DaemonClient()
        result = client.read_characteristic(address, uuid=uuid, handle=handle, format=format)
        formatter.print(result)
    except Exception as e:
        formatter.print_error(str(e))


@app.command("write")
def ble_write(
    address: str = typer.Argument(..., help="Device address or alias"),
    uuid: Optional[str] = typer.Option(None, "--uuid", "-u", help="Characteristic UUID"),
    handle: Optional[int] = typer.Option(None, "--handle", "-H", help="Characteristic handle (alternative to UUID)"),
    data: str = typer.Option(..., "--data", "-d", help="Data to write (hex:/text:/base64: prefix)"),
    response: bool = typer.Option(False, "--response/--no-response", help="Request write response"),
    human: bool = typer.Option(False, "-h", "--human", help="Human-readable output (default: JSON)"),
) -> None:
    """Write to a characteristic."""
    formatter = OutputFormatter(json_output=not human)
    
    if not uuid and not handle:
        formatter.print_error("Either --uuid or --handle must be specified")
        return
    
    try:
        from airctl.daemon.auto_start import ensure_daemon_running
        from airctl.ipc.client import DaemonClient
        
        ensure_daemon_running()
        
        client = DaemonClient()
        client.write_characteristic(address, uuid=uuid, handle=handle, data=data, response=response)
        target = f"handle {handle}" if handle else uuid
        formatter.print_success(f"Written to {target}")
    except Exception as e:
        formatter.print_error(str(e))


notify_app = typer.Typer(help="Notification commands")
app.add_typer(notify_app, name="notify")


@notify_app.command("subscribe")
def notify_subscribe(
    address: str = typer.Argument(..., help="Device address or alias"),
    uuid: str = typer.Option(..., "--uuid", "-u", help="Characteristic UUID"),
    human: bool = typer.Option(False, "-h", "--human", help="Human-readable output (default: JSON)"),
) -> None:
    """Subscribe to characteristic notifications."""
    formatter = OutputFormatter(json_output=not human)
    
    try:
        from airctl.daemon.auto_start import ensure_daemon_running
        from airctl.ipc.client import DaemonClient
        
        ensure_daemon_running()
        
        client = DaemonClient()
        client.subscribe_notification(address, uuid)
        formatter.print_success(f"Subscribed to {uuid}")
    except Exception as e:
        formatter.print_error(str(e))


@notify_app.command("unsubscribe")
def notify_unsubscribe(
    address: str = typer.Argument(..., help="Device address or alias"),
    uuid: str = typer.Option(..., "--uuid", "-u", help="Characteristic UUID"),
    human: bool = typer.Option(False, "-h", "--human", help="Human-readable output (default: JSON)"),
) -> None:
    """Unsubscribe from characteristic notifications."""
    formatter = OutputFormatter(json_output=not human)
    
    try:
        from airctl.daemon.auto_start import ensure_daemon_running
        from airctl.ipc.client import DaemonClient
        
        ensure_daemon_running()
        
        client = DaemonClient()
        client.unsubscribe_notification(address, uuid)
        formatter.print_success(f"Unsubscribed from {uuid}")
    except Exception as e:
        formatter.print_error(str(e))


@app.command("events")
def ble_events(
    address: Optional[str] = typer.Option(None, "--address", "-a", help="Filter by device address"),
    event_type: Optional[str] = typer.Option(None, "--type", "-t", help="Filter by event type"),
) -> None:
    """Stream BLE events (notifications, disconnections, etc.)."""
    try:
        from airctl.daemon.auto_start import ensure_daemon_running
        from airctl.ipc.client import DaemonClient
        
        ensure_daemon_running()
        
        client = DaemonClient()
        
        import sys
        
        for event in client.stream_events(address=address, event_type=event_type):
            sys.stdout.write(event + "\n")
            sys.stdout.flush()
    except KeyboardInterrupt:
        pass
    except Exception as e:
        console.print(f'[red]Error:[/red] {e}')
