"""
🦞 BlueLobster CLI - Vibe coding from your couch.

Productivity is a jumpscare.
"""

import asyncio
import logging
import signal
import sys
from typing import Optional

import click

from . import __version__
from .audio import play_jumpscare, cleanup as audio_cleanup
from .ws_client import MoltbotClient, DEFAULT_WS_URL
from .ble_server import BLEServer, BLEConfig, get_setup_instructions


# Configure logging
def setup_logging(verbose: bool) -> None:
    """Configure logging based on verbosity."""
    level = logging.DEBUG if verbose else logging.INFO
    logging.basicConfig(
        level=level,
        format="%(message)s" if not verbose else "%(asctime)s [%(levelname)s] %(name)s: %(message)s",
        handlers=[logging.StreamHandler()],
    )


@click.group()
@click.version_option(version=__version__, prog_name="bluelobster")
def cli():
    """
    BlueLobster - A lazy-ass BLE bridge for Moltbot (formerly Clawdbot)
    
    Optimized for horizontal development.
    Molt your responsibilities, keep the gains.
    """
    pass


@cli.command()
@click.option(
    "--ws-url",
    default=DEFAULT_WS_URL,
    help=f"Moltbot WebSocket URL (default: {DEFAULT_WS_URL})",
)
@click.option(
    "--token",
    default=None,
    help="Moltbot authentication token",
)
@click.option(
    "--no-audio",
    is_flag=True,
    help="Disable the jumpscare audio (you coward)",
)
@click.option(
    "--audio-file",
    default=None,
    type=click.Path(exists=True),
    help="Custom audio file for jumpscare",
)
@click.option(
    "-v", "--verbose",
    is_flag=True,
    help="Enable verbose logging",
)
def start(
    ws_url: str,
    token: Optional[str],
    no_audio: bool,
    audio_file: Optional[str],
    verbose: bool,
):
    """
    Start the BlueLobster bridge.
    
    Starts the BLE server and connects to Moltbot.
    Send messages from your phone and watch the magic happen.
    """
    setup_logging(verbose)
    logger = logging.getLogger(__name__)
    
    # Print the glorious banner
    click.echo(_get_banner())
    
    async def run():
        # BLE server reference (set after creation)
        ble = None
        
        # Track the last sent text to calculate deltas manually if needed
        last_sent_text = ""
        current_request_id = None
        
        # Response handler - forwards Clawdbot responses to iOS
        async def on_moltbot_response(raw_message: str):
            """Handle incoming response from Clawdbot."""
            import json
            # Need to use nonlocal to modify closure variables
            nonlocal last_sent_text
            nonlocal current_request_id
            
            try:
                data = json.loads(raw_message)
                msg_type = data.get("type")
                event = data.get("event")
                
                # Log everything except health/tick to debug
                if event not in ["health", "tick", "voicewake.changed"]:
                    # logger.info(f"📥 WS Message: type={msg_type} event={event}")
                    pass
                
                if msg_type == "event" and event == "agent":
                    # Agent streaming output
                    payload = data.get("payload", {})
                    
                    # Reset tracker if this is a new run
                    run_id = payload.get("runId")
                    # logger.info(f"Run ID: {run_id} Current: {current_request_id}")
                    
                    if run_id and run_id != current_request_id:
                        logger.info(f"🆕 New response sequence started: {run_id}")
                        current_request_id = run_id
                        last_sent_text = ""
                        
                    # Clawdbot v3 streams 'delta' or 'data' for text changes
                    delta = payload.get("delta", "")
                    content = payload.get("content", "")
                    data_obj = payload.get("data", "")
                    
                    # Extract text from data object if it's a dict
                    if isinstance(data_obj, dict):
                        # Try common keys
                        data_text = data_obj.get("text") or data_obj.get("content") or data_obj.get("delta") or ""
                        # If still empty but we have a dict, might be structured data
                        if not data_text and data_obj:
                             # For now, just skip complex structured data to avoid spamming JSON
                             data_text = "" 
                    else:
                        data_text = str(data_obj) if data_obj else ""
                    
                    # Determine what text we have
                    full_text = content or data_text
                    
                    # If we have explicit delta, use it
                    text_to_send = ""
                    if delta:
                        text_to_send = delta
                    elif full_text:
                        # If we have full text, calculate diff
                        if full_text.startswith(last_sent_text):
                            text_to_send = full_text[len(last_sent_text):]
                            last_sent_text = full_text
                        else:
                            # Context reset or out of order? Just send all
                            text_to_send = full_text
                            last_sent_text = full_text
                    
                    if text_to_send and isinstance(text_to_send, str):
                        if ble:
                            success = ble.send_notification(text_to_send)
                            if success:
                                # Use info so we can see it in default logs
                                logger.info(f"📲 Sent to iOS: {text_to_send[:50]}")
                            else:
                                logger.warning(f"⚠️ BLE send failed (len={len(text_to_send)})")
                        else:
                            logger.warning("⚠️ Received response but BLE server not ready")
                        
                elif msg_type == "event" and event == "chat":
                    # Chat final state
                    payload = data.get("payload", {})
                    # logger.info(f"Chat event: {payload}")
                    if payload.get("state") == "final":
                        # Also check if there's content in the chat event?
                        # Sometimes final event has the full text?
                        logger.info("✅ Agent response complete")
                        # Reset for next time
                        last_sent_text = ""
                        current_request_id = None
                        
            except json.JSONDecodeError:
                pass
            except Exception as e:
                logger.error(f"Response handler error: {e}")
        
        # Create Moltbot client with response handler
        moltbot = MoltbotClient(
            ws_url=ws_url,
            token=token,
            on_response=on_moltbot_response
        )
        
        # Message handler - forwards iOS messages to Clawdbot
        async def on_ble_message(text: str):
            """Handle incoming BLE message."""
            logger.info(f"🦞 Received: {text}")
            
            # Play the jumpscare
            if not no_audio:
                play_jumpscare(audio_path=audio_file)
            
            # Forward to Moltbot
            success = await moltbot.send_message(text)
            if not success:
                logger.warning("⚠️ Failed to forward to Moltbot")
        
        # Create and start BLE server
        ble = BLEServer(on_message=on_ble_message)
        
        # Handle shutdown
        shutdown_event = asyncio.Event()
        
        def signal_handler():
            logger.info("\n🦞 Molting time! Shutting down...")
            shutdown_event.set()
        
        loop = asyncio.get_event_loop()
        for sig in (signal.SIGINT, signal.SIGTERM):
            loop.add_signal_handler(sig, signal_handler)
        
        try:
            # Connect to Moltbot
            connected = await moltbot.connect()
            if not connected:
                logger.warning("⚠️ Could not connect to Moltbot - will retry on first message")
            
            # Start BLE server
            started = await ble.start()
            if not started:
                logger.error("❌ Failed to start BLE server")
                return
            
            click.echo("\n" + get_setup_instructions())
            click.echo("\nBlueLobster is ready! Waiting for messages...\n")
            
            # Wait for shutdown
            await shutdown_event.wait()
            
        finally:
            await ble.stop()
            await moltbot.disconnect()
            audio_cleanup()
    
    try:
        asyncio.run(run())
    except KeyboardInterrupt:
        pass


@cli.command()
def setup():
    """
    📱 Show mobile app setup instructions.
    
    Displays the UUIDs needed to connect your phone to BlueLobster.
    """
    click.echo(get_setup_instructions())


@cli.command()
@click.option(
    "--audio-file",
    default=None,
    type=click.Path(exists=True),
    help="Custom audio file to test",
)
def test_audio(audio_file: Optional[str]):
    """
    🎵 Test the jumpscare audio.
    
    Make sure your speakers are ready for Bach.
    """
    setup_logging(False)
    click.echo("🦞 Playing jumpscare audio...")
    click.echo("🎵 (Bach's Toccata and Fugue in D minor)")
    
    success = play_jumpscare(audio_path=audio_file, blocking=True)
    
    if success:
        click.echo("✅ Audio played successfully!")
    else:
        click.echo("❌ Audio failed to play")
        click.echo("💡 Make sure you have a jumpscare.mp3 file in:")
        click.echo("   - ./assets/jumpscare.mp3")
        click.echo("   - ~/.bluelobster/jumpscare.mp3")
    
    audio_cleanup()


@cli.command()
@click.argument("message")
@click.option(
    "--ws-url",
    default=DEFAULT_WS_URL,
    help=f"Moltbot WebSocket URL (default: {DEFAULT_WS_URL})",
)
@click.option(
    "--token",
    default=None,
    help="Moltbot authentication token",
)
def send(message: str, ws_url: str, token: Optional[str]):
    """
    📤 Send a test message to Moltbot.
    
    Useful for testing the WebSocket connection without BLE.
    """
    setup_logging(False)
    
    async def _send():
        client = MoltbotClient(ws_url=ws_url, token=token)
        try:
            if await client.connect():
                success = await client.send_message(message)
                if success:
                    click.echo(f"✅ Sent: {message}")
                else:
                    click.echo("❌ Failed to send message")
            else:
                click.echo("❌ Failed to connect to Moltbot")
        finally:
            await client.disconnect()
    
    asyncio.run(_send())


def _get_banner() -> str:
    """Get the glorious BlueLobster ASCII banner."""
    return r"""
    ╔═══════════════════════════════════════════════════════════════╗
    ║                                                               ║
    ║   🦞  ____  _            _          _         _               ║
    ║      | __ )| |_   _  ___| |    ___ | |__  ___| |_ ___ _ __    ║
    ║      |  _ \| | | | |/ _ \ |   / _ \| '_ \/ __| __/ _ \ '__|   ║
    ║      | |_) | | |_| |  __/ |__| (_) | |_) \__ \ ||  __/ |      ║
    ║      |____/|_|\__,_|\___|_____\___/|_.__/|___/\__\___|_|      ║
    ║                                                               ║
    ║        Optimized for horizontal development. 🛋️               ║
    ║        Productivity is a jumpscare.                           ║
    ║                                                               ║
    ╚═══════════════════════════════════════════════════════════════╝
    """


if __name__ == "__main__":
    cli()
