"""
Vocal Bridge CLI - Developer tools for voice agent iteration.

Install: pip install vocal-bridge
Usage: vb --help

Requirements: Python 3.9+
"""

__version__ = "0.4.0"

import argparse
import asyncio
import json
import os
import sys
import tempfile
import subprocess
import urllib.request
import urllib.error
import time
import signal
from datetime import datetime
from pathlib import Path
from typing import Optional, Dict, Any

try:
    import websockets
    HAS_WEBSOCKETS = True
except ImportError:
    HAS_WEBSOCKETS = False

# ========================================
# Configuration
# ========================================

CONFIG_DIR = Path.home() / ".vocal-bridge"
DEFAULT_API_URL = "https://vocalbridgeai.com"


def get_config_dir() -> Path:
    CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    return CONFIG_DIR


def load_config() -> dict:
    config_file = get_config_dir() / "config.json"
    if config_file.exists():
        try:
            with open(config_file, "r") as f:
                return json.load(f)
        except (json.JSONDecodeError, IOError):
            return {}
    return {}


def save_config(config: dict) -> None:
    config_file = get_config_dir() / "config.json"
    with open(config_file, "w") as f:
        json.dump(config, f, indent=2)
    os.chmod(config_file, 0o600)


def get_api_key() -> Optional[str]:
    env_key = os.environ.get("VOCAL_BRIDGE_API_KEY")
    if env_key:
        return env_key
    return load_config().get("api_key")


def set_api_key(api_key: str) -> None:
    config = load_config()
    config["api_key"] = api_key
    save_config(config)


def get_api_url() -> str:
    env_url = os.environ.get("VOCAL_BRIDGE_API_URL")
    if env_url:
        return env_url.rstrip("/")
    return load_config().get("api_url", DEFAULT_API_URL).rstrip("/")


def set_api_url(api_url: str) -> None:
    config = load_config()
    config["api_url"] = api_url.rstrip("/")
    save_config(config)


def clear_config() -> None:
    config_file = get_config_dir() / "config.json"
    if config_file.exists():
        config_file.unlink()


# ========================================
# API Client (using stdlib urllib)
# ========================================


class APIError(Exception):
    def __init__(self, status_code: int, detail: str):
        self.status_code = status_code
        self.detail = detail
        super().__init__(f"API error ({status_code}): {detail}")


def api_request(
    method: str,
    endpoint: str,
    api_key: Optional[str] = None,
    api_url: Optional[str] = None,
    data: Optional[dict] = None,
    params: Optional[dict] = None,
) -> Dict[str, Any]:
    """Make an API request using urllib."""
    key = api_key or get_api_key()
    url = api_url or get_api_url()

    if not key:
        raise ValueError("No API key found. Run 'vb auth login' or set VOCAL_BRIDGE_API_KEY")

    full_url = f"{url}{endpoint}"
    if params:
        query = "&".join(f"{k}={v}" for k, v in params.items() if v is not None)
        if query:
            full_url = f"{full_url}?{query}"

    headers = {
        "X-API-Key": key,
        "Content-Type": "application/json",
    }

    body = json.dumps(data).encode("utf-8") if data else None

    req = urllib.request.Request(full_url, data=body, headers=headers, method=method)

    try:
        with urllib.request.urlopen(req, timeout=30) as response:
            return json.loads(response.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        try:
            detail = json.loads(e.read().decode("utf-8")).get("detail", str(e))
        except Exception:
            detail = str(e)
        raise APIError(e.code, detail)
    except urllib.error.URLError as e:
        raise APIError(0, f"Connection failed: {e.reason}")


def api_download(
    endpoint: str,
    api_key: Optional[str] = None,
    api_url: Optional[str] = None,
) -> tuple[bytes, str, str]:
    """Download binary data from an API endpoint.

    Returns:
        Tuple of (data, content_type, filename)
    """
    key = api_key or get_api_key()
    url = api_url or get_api_url()

    if not key:
        raise ValueError("No API key found. Run 'vb auth login' or set VOCAL_BRIDGE_API_KEY")

    full_url = f"{url}{endpoint}"

    headers = {
        "X-API-Key": key,
    }

    req = urllib.request.Request(full_url, headers=headers, method="GET")

    try:
        with urllib.request.urlopen(req, timeout=60) as response:
            data = response.read()
            content_type = response.headers.get("Content-Type", "application/octet-stream")

            # Extract filename from Content-Disposition header
            content_disposition = response.headers.get("Content-Disposition", "")
            filename = "recording"
            if 'filename="' in content_disposition:
                start = content_disposition.index('filename="') + 10
                end = content_disposition.index('"', start)
                filename = content_disposition[start:end]
            elif "filename=" in content_disposition:
                start = content_disposition.index("filename=") + 9
                end = content_disposition.find(";", start)
                if end == -1:
                    end = len(content_disposition)
                filename = content_disposition[start:end].strip()

            return data, content_type, filename
    except urllib.error.HTTPError as e:
        try:
            detail = json.loads(e.read().decode("utf-8")).get("detail", str(e))
        except Exception:
            detail = str(e)
        raise APIError(e.code, detail)
    except urllib.error.URLError as e:
        raise APIError(0, f"Connection failed: {e.reason}")


# ========================================
# Formatting Helpers
# ========================================


def format_datetime(dt_str: Optional[str]) -> str:
    if not dt_str:
        return "-"
    try:
        dt = datetime.fromisoformat(dt_str.replace("Z", "+00:00"))
        return dt.strftime("%Y-%m-%d %H:%M:%S")
    except Exception:
        return dt_str


def format_duration(seconds: Optional[int]) -> str:
    if seconds is None:
        return "-"
    minutes, secs = divmod(seconds, 60)
    if minutes > 0:
        return f"{minutes}m {secs}s"
    return f"{secs}s"


def print_error(message: str) -> None:
    print(f"Error: {message}", file=sys.stderr)


def print_warning(message: str) -> None:
    print(f"Warning: {message}", file=sys.stderr)


def print_success(message: str) -> None:
    print(f"OK: {message}")


# ========================================
# Auth Commands
# ========================================


def cmd_auth_login(args: argparse.Namespace) -> int:
    api_key = args.api_key

    if not api_key:
        try:
            api_key = input("Enter your API key: ").strip()
        except (KeyboardInterrupt, EOFError):
            print()
            return 1

    if not api_key:
        print_error("No API key provided")
        return 1

    if not api_key.startswith("vb_"):
        print_error("Invalid API key format (should start with 'vb_')")
        return 1

    if args.api_url:
        set_api_url(args.api_url)

    print("Verifying API key...")
    try:
        agent = api_request("GET", "/api/v1/agent", api_key=api_key, api_url=args.api_url)
    except APIError as e:
        if e.status_code == 401:
            print_error("Invalid API key")
        elif e.status_code == 404:
            print_error("Agent not found for this API key")
        else:
            print_error(f"API error: {e.detail}")
        return 1
    except Exception as e:
        print_error(f"Connection failed: {e}")
        return 1

    set_api_key(api_key)
    print_success(f"Authenticated as agent '{agent['name']}' ({agent['mode']} mode)")
    return 0


def cmd_auth_logout(args: argparse.Namespace) -> int:
    clear_config()
    print_success("Logged out successfully")
    return 0


def cmd_auth_status(args: argparse.Namespace) -> int:
    api_key = get_api_key()
    api_url = get_api_url()

    if not api_key:
        print("Status: Not authenticated")
        print(f"API URL: {api_url}")
        print("\nRun 'vb auth login' to authenticate")
        return 1

    print(f"API URL: {api_url}")
    print(f"API Key: {api_key[:12]}...{api_key[-4:]}")

    try:
        agent = api_request("GET", "/api/v1/agent")
        print("Status: Authenticated")
        print(f"Agent: {agent['name']} ({agent['mode']} mode)")
        print(f"Agent ID: {agent['id']}")
        if agent.get("phone_number"):
            print(f"Phone: {agent['phone_number']}")
        return 0
    except APIError as e:
        print(f"Status: Invalid ({e.detail})")
        return 1
    except Exception as e:
        print(f"Status: Unable to verify ({e})")
        return 1


# ========================================
# Agent Commands
# ========================================


def cmd_agent(args: argparse.Namespace) -> int:
    try:
        agent = api_request("GET", "/api/v1/agent")

        print(f"Agent: {agent['name']}")
        print(f"ID: {agent['id']}")
        print(f"Mode: {agent['mode']}")
        print(f"Status: {agent['deployment_status']}")
        if agent.get("phone_number"):
            print(f"Phone: {agent['phone_number']}")
        if agent.get("greeting"):
            print(f"Greeting: {agent['greeting']}")
        print(f"Created: {format_datetime(agent.get('created_at'))}")
        return 0
    except ValueError as e:
        print_error(str(e))
        return 1
    except APIError as e:
        print_error(e.detail)
        return 1
    except Exception as e:
        print_error(f"Failed to get agent info: {e}")
        return 1


# ========================================
# Logs Commands
# ========================================


def cmd_logs_list(args: argparse.Namespace) -> int:
    try:
        params = {"limit": args.limit, "offset": args.offset}
        if args.status:
            params["status"] = args.status

        result = api_request("GET", "/api/v1/logs", params=params)
        sessions = result.get("sessions", [])
        total = result.get("total", 0)

        if not sessions:
            print("No call logs found")
            return 0

        print(f"{'ID':<36}  {'Started':<19}  {'Duration':<10}  {'Status':<12}  {'Messages'}")
        print("-" * 100)

        for session in sessions:
            session_id = session.get("id", "-")
            started = format_datetime(session.get("started_at"))
            duration = format_duration(session.get("duration_seconds"))
            status = session.get("status", "-")
            messages = session.get("message_count", "-")

            status_display = status
            if status == "completed":
                status_display = f"\033[32m{status}\033[0m"
            elif status == "failed":
                status_display = f"\033[31m{status}\033[0m"
            elif status == "in_progress":
                status_display = f"\033[33m{status}\033[0m"

            print(f"{session_id}  {started}  {duration:<10}  {status_display:<21}  {messages}")

        print(f"\nShowing {len(sessions)} of {total} sessions")

        if args.json:
            print("\n--- JSON ---")
            print(json.dumps(result, indent=2))

        return 0
    except ValueError as e:
        print_error(str(e))
        return 1
    except APIError as e:
        print_error(e.detail)
        return 1
    except Exception as e:
        print_error(f"Failed to get logs: {e}")
        return 1


def cmd_logs_detail(args: argparse.Namespace) -> int:
    try:
        session = api_request("GET", f"/api/v1/logs/{args.session_id}")

        print(f"Session: {session.get('id')}")
        print(f"Status: {session.get('status')}")
        print(f"Started: {format_datetime(session.get('started_at'))}")
        print(f"Ended: {format_datetime(session.get('ended_at'))}")
        print(f"Duration: {format_duration(session.get('duration_seconds'))}")
        print(f"Messages: {session.get('message_count', '-')}")
        if session.get("caller_phone"):
            print(f"Caller: {session.get('caller_phone')}")
        if session.get("call_direction"):
            print(f"Direction: {session.get('call_direction')}")
        if session.get("error_message"):
            print(f"Error: {session.get('error_message')}")
        if session.get("has_recording"):
            print(f"Recording: Available (use 'vb logs download {args.session_id}' to download)")

        transcript_text = session.get("transcript_text")
        if transcript_text:
            print("\n--- Transcript ---")
            print(transcript_text)
        elif session.get("transcript"):
            print("\n--- Transcript ---")
            for msg in session.get("transcript", []):
                role = msg.get("role", "unknown")
                content = msg.get("content", "")
                print(f"[{role}] {content}")

        if args.json:
            print("\n--- Full JSON ---")
            print(json.dumps(session, indent=2))

        return 0
    except ValueError as e:
        print_error(str(e))
        return 1
    except APIError as e:
        print_error(e.detail)
        return 1
    except Exception as e:
        print_error(f"Failed to get log detail: {e}")
        return 1


def sanitize_filename(filename: str) -> str:
    """Sanitize filename to prevent path traversal attacks.

    Removes directory components and dangerous characters.
    """
    # Get just the basename (remove any directory components)
    filename = os.path.basename(filename)

    # Remove any remaining path separators (shouldn't be any after basename)
    filename = filename.replace("/", "_").replace("\\", "_")

    # Remove null bytes and other control characters
    filename = "".join(c for c in filename if c.isprintable() and c not in '<>:"|?*')

    # Ensure filename isn't empty or just dots
    if not filename or filename in (".", ".."):
        filename = "recording.ogg"

    return filename


def cmd_logs_download(args: argparse.Namespace) -> int:
    """Download the call recording for a session."""
    try:
        # Download the recording
        data, content_type, filename = api_download(f"/api/v1/logs/{args.session_id}/recording")

        # Sanitize server-provided filename to prevent path traversal
        filename = sanitize_filename(filename)

        # Use custom output path if provided
        if args.output:
            output_path = args.output
        else:
            output_path = filename

        # Write to file
        with open(output_path, "wb") as f:
            f.write(data)

        size_kb = len(data) / 1024
        if size_kb >= 1024:
            size_str = f"{size_kb / 1024:.1f} MB"
        else:
            size_str = f"{size_kb:.1f} KB"

        print_success(f"Downloaded recording to {output_path} ({size_str})")
        return 0
    except ValueError as e:
        print_error(str(e))
        return 1
    except APIError as e:
        if e.status_code == 404:
            print_error("No recording available for this session")
        else:
            print_error(e.detail)
        return 1
    except IOError as e:
        print_error(f"Failed to write file: {e}")
        return 1
    except Exception as e:
        print_error(f"Failed to download recording: {e}")
        return 1


def cmd_stats(args: argparse.Namespace) -> int:
    try:
        stats = api_request("GET", "/api/v1/logs/stats")

        print("Call Statistics")
        print("-" * 40)
        print(f"Total Sessions: {stats.get('total_sessions', 0)}")
        print(f"  Completed: {stats.get('completed_sessions', 0)}")
        print(f"  Failed: {stats.get('failed_sessions', 0)}")
        print(f"  Abandoned: {stats.get('abandoned_sessions', 0)}")
        print()
        print(f"Total Duration: {format_duration(stats.get('total_duration_seconds', 0))}")
        print(f"Avg Duration: {format_duration(int(stats.get('avg_duration_seconds', 0)))}")
        print(f"Total Messages: {stats.get('total_messages', 0)}")
        print(f"Avg Messages: {stats.get('avg_messages', 0):.1f}")

        if args.json:
            print("\n--- JSON ---")
            print(json.dumps(stats, indent=2))

        return 0
    except ValueError as e:
        print_error(str(e))
        return 1
    except APIError as e:
        print_error(e.detail)
        return 1
    except Exception as e:
        print_error(f"Failed to get stats: {e}")
        return 1


# ========================================
# Prompt Commands
# ========================================


def cmd_prompt_show(args: argparse.Namespace) -> int:
    try:
        agent = api_request("GET", "/api/v1/agent")

        prompt = agent.get("custom_prompt")
        greeting = agent.get("greeting")

        if greeting:
            print("--- Greeting ---")
            print(greeting)
            print()

        if prompt:
            print("--- System Prompt ---")
            print(prompt)
        else:
            print("No custom prompt set")

        return 0
    except ValueError as e:
        print_error(str(e))
        return 1
    except APIError as e:
        print_error(e.detail)
        return 1
    except Exception as e:
        print_error(f"Failed to get prompt: {e}")
        return 1


def cmd_prompt_set(args: argparse.Namespace) -> int:
    try:
        if args.file:
            with open(args.file, "r") as f:
                content = f.read()
        elif not sys.stdin.isatty():
            content = sys.stdin.read()
        else:
            print_error("Provide prompt via --file or pipe to stdin")
            print("Example: echo 'You are a helpful assistant.' | vb prompt set")
            print("Example: vb prompt set --file prompt.txt")
            return 1

        content = content.strip()
        if not content:
            print_error("Empty prompt")
            return 1

        data = {"greeting": content} if args.greeting else {"prompt": content}
        api_request("PATCH", "/api/v1/agent/prompt", data=data)

        field = "Greeting" if args.greeting else "Prompt"
        print_success(f"{field} updated ({len(content)} chars)")
        return 0
    except ValueError as e:
        print_error(str(e))
        return 1
    except APIError as e:
        print_error(e.detail)
        return 1
    except FileNotFoundError:
        print_error(f"File not found: {args.file}")
        return 1
    except Exception as e:
        print_error(f"Failed to update prompt: {e}")
        return 1


def cmd_prompt_edit(args: argparse.Namespace) -> int:
    try:
        agent = api_request("GET", "/api/v1/agent")

        if args.greeting:
            content = agent.get("greeting", "")
            field_name = "greeting"
        else:
            content = agent.get("custom_prompt", "")
            field_name = "prompt"

        editor = os.environ.get("EDITOR", os.environ.get("VISUAL", "vi"))

        with tempfile.NamedTemporaryFile(mode="w", suffix=f".{field_name}.txt", delete=False) as f:
            f.write(content or "")
            temp_path = f.name

        try:
            result = subprocess.run([editor, temp_path])
            if result.returncode != 0:
                print_error("Editor exited with error")
                return 1

            with open(temp_path, "r") as f:
                new_content = f.read().strip()

            if new_content == (content or "").strip():
                print("No changes made")
                return 0

            data = {"greeting": new_content} if args.greeting else {"prompt": new_content}
            api_request("PATCH", "/api/v1/agent/prompt", data=data)

            print_success(f"{field_name.capitalize()} updated ({len(new_content)} chars)")
            return 0
        finally:
            try:
                os.unlink(temp_path)
            except Exception:
                pass

    except ValueError as e:
        print_error(str(e))
        return 1
    except APIError as e:
        print_error(e.detail)
        return 1
    except Exception as e:
        print_error(f"Failed to edit prompt: {e}")
        return 1


# ========================================
# Debug Commands
# ========================================

# Event type colors for terminal output
EVENT_COLORS = {
    'user_transcription': '\033[34m',    # Blue
    'agent_response': '\033[32m',        # Green
    'tool_call': '\033[33m',             # Yellow
    'tool_result': '\033[35m',           # Purple/Magenta
    'background_query': '\033[36m',      # Cyan
    'background_result': '\033[36m',     # Cyan
    'error': '\033[31m',                 # Red
    'session_started': '\033[90m',       # Gray
    'session_ended': '\033[90m',         # Gray
    'state_change': '\033[90m',          # Gray
    'hold_started': '\033[38;5;208m',    # Orange
    'hold_ended': '\033[38;5;208m',      # Orange
}
COLOR_RESET = '\033[0m'

EVENT_LABELS = {
    'user_transcription': 'USER',
    'agent_response': 'AGENT',
    'tool_call': 'TOOL',
    'tool_result': 'RESULT',
    'background_query': 'BG QUERY',
    'background_result': 'BG RESULT',
    'error': 'ERROR',
    'session_started': 'SESSION',
    'session_ended': 'SESSION',
    'state_change': 'STATE',
    'hold_started': 'HOLD',
    'hold_ended': 'HOLD',
}


def format_debug_event(event: dict) -> str:
    """Format a debug event for terminal output."""
    event_type = event.get("event_type", "unknown")
    data = event.get("data", {})
    timestamp = event.get("timestamp", "")

    # Format timestamp
    time_str = ""
    if timestamp:
        try:
            dt = datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
            time_str = dt.strftime("%H:%M:%S")
        except Exception:
            time_str = timestamp[:8] if len(timestamp) >= 8 else timestamp

    # Get color and label
    color = EVENT_COLORS.get(event_type, '')
    label = EVENT_LABELS.get(event_type, event_type.upper())

    # Format data based on event type (no truncation - output full data)
    data_str = ""
    if isinstance(data, str):
        data_str = data
    elif isinstance(data, dict):
        if event_type == "tool_call":
            # Show tool name and full arguments
            name = data.get("name", "unknown")
            args = data.get("arguments", "")
            if isinstance(args, str):
                args_str = args
            else:
                args_str = json.dumps(args)
            data_str = f"{name}({args_str})"
        elif event_type == "tool_result":
            # Show tool name and full result
            name = data.get("name", "unknown")
            result = str(data.get("result", ""))
            is_error = data.get("is_error", False)
            status = "ERROR" if is_error else "OK"
            data_str = f"{name} [{status}]: {result}"
        elif event_type == "background_query":
            query = data.get("query", "")
            job_id = data.get("job_id", "")
            data_str = f"[{job_id[:8] if job_id else 'no-id'}] {query}"
        elif event_type == "background_result":
            job_id = data.get("job_id", "")
            result = str(data.get("result", ""))
            success = data.get("success", True)
            status = "OK" if success else "FAILED"
            data_str = f"[{job_id[:8] if job_id else 'no-id'}] [{status}] {result}"
        elif data.get("transcript"):
            data_str = data["transcript"]
        elif data.get("text"):
            data_str = data["text"]
        elif data.get("message"):
            data_str = data["message"]
        elif data.get("query"):
            data_str = data["query"]
        else:
            data_str = json.dumps(data)

    return f"[{time_str}] {color}{label:>12}{COLOR_RESET}  {data_str}"


async def _debug_websocket_stream(ws_url: str, agent_name: str) -> int:
    """Stream debug events via WebSocket."""
    import websockets

    print(f"Debug Stream: {agent_name}")
    print("-" * 50)
    print("Connected via WebSocket (real-time)")
    print("Waiting for events... (Ctrl+C to stop)")
    print()

    event_count = 0

    try:
        async with websockets.connect(ws_url) as ws:
            while True:
                try:
                    message = await ws.recv()
                    data = json.loads(message)

                    # Handle different message types
                    msg_type = data.get("type")
                    if msg_type == "debug_event":
                        # Format as expected by format_debug_event
                        event = {
                            "event_type": data.get("event_type"),
                            "data": data.get("data"),
                            "timestamp": data.get("timestamp"),
                            "session_id": data.get("session_id")
                        }
                        print(format_debug_event(event))
                        event_count += 1
                    elif msg_type == "connected":
                        # Connection confirmation
                        agent_name = data.get("agent_name", "Unknown")
                        print(f"Connected to: {agent_name}")
                        print()
                    elif msg_type == "error":
                        print_error(f"Server error: {data.get('message', 'Unknown error')}")
                        break

                except websockets.ConnectionClosed:
                    print("\nWebSocket connection closed")
                    break

    except asyncio.CancelledError:
        pass
    except Exception as e:
        print_error(f"WebSocket error: {e}")
        return 1

    print(f"\nTotal events received: {event_count}")
    return 0


def _debug_polling_stream(agent_name: str, poll_interval: float) -> int:
    """Stream debug events via HTTP polling (fallback)."""
    print(f"Debug Stream: {agent_name}")
    print("-" * 50)
    print(f"Using HTTP polling (interval: {poll_interval}s)")
    print("Waiting for events... (Ctrl+C to stop)")
    print()

    # Track the last timestamp for polling
    last_timestamp = None

    # Handle Ctrl+C gracefully
    running = True

    def signal_handler(signum, frame):
        nonlocal running
        running = False
        print("\n\nStopping debug stream...")

    signal.signal(signal.SIGINT, signal_handler)

    event_count = 0
    while running:
        try:
            params = {"limit": 100}
            if last_timestamp:
                params["since"] = last_timestamp

            result = api_request("GET", "/api/v1/debug/events", params=params)
            events = result.get("events", [])

            for event in events:
                print(format_debug_event(event))
                event_count += 1

            if result.get("last_timestamp"):
                last_timestamp = result["last_timestamp"]

            time.sleep(poll_interval)

        except APIError as e:
            if e.status_code == 400 and "debug mode" in e.detail.lower():
                print_error("Debug mode is not enabled for this agent.")
                print("\nTo enable debug mode:")
                print("  1. Go to your agent in the Vocal Bridge dashboard")
                print("  2. Click 'Edit'")
                print("  3. Enable 'Debug Mode' in the Capabilities section")
                print("  4. Save changes")
                return 1
            raise
        except KeyboardInterrupt:
            break

    print(f"\nTotal events received: {event_count}")
    return 0


def cmd_debug(args: argparse.Namespace) -> int:
    """Stream real-time debug events from the agent."""
    try:
        # First get agent info
        agent = api_request("GET", "/api/v1/agent")
        agent_name = agent.get("name", "Unknown")

        # Check if we should use polling mode
        use_polling = getattr(args, 'poll', False)

        # Use WebSocket if available and not forced to poll
        if HAS_WEBSOCKETS and not use_polling:
            try:
                # Get WebSocket token
                token_response = api_request("POST", "/api/v1/debug/token")
                ws_url = token_response.get("ws_url")

                if ws_url:
                    # Run the async WebSocket stream
                    try:
                        return asyncio.run(_debug_websocket_stream(ws_url, agent_name))
                    except KeyboardInterrupt:
                        print("\n\nStopping debug stream...")
                        return 0
                else:
                    print_warning("WebSocket URL not available, falling back to polling")
                    use_polling = True

            except APIError as e:
                if e.status_code == 400 and "debug mode" in e.detail.lower():
                    print_error("Debug mode is not enabled for this agent.")
                    print("\nTo enable debug mode:")
                    print("  1. Go to your agent in the Vocal Bridge dashboard")
                    print("  2. Click 'Edit'")
                    print("  3. Enable 'Debug Mode' in the Capabilities section")
                    print("  4. Save changes")
                    return 1
                # Fall back to polling on other errors
                print_warning(f"WebSocket setup failed: {e.detail}, falling back to polling")
                use_polling = True

        if not HAS_WEBSOCKETS and not use_polling:
            print_warning("websockets package not installed, using HTTP polling")
            print("Install with: pip install websockets")
            print()

        # Use polling mode
        poll_interval = float(args.interval) if hasattr(args, 'interval') else 0.5
        return _debug_polling_stream(agent_name, poll_interval)

    except ValueError as e:
        print_error(str(e))
        return 1
    except APIError as e:
        print_error(e.detail)
        return 1
    except Exception as e:
        print_error(f"Debug stream failed: {e}")
        return 1


# ========================================
# Main Entry Point
# ========================================


def create_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog="vb",
        description="Vocal Bridge CLI - Developer tools for voice agent iteration",
    )
    parser.add_argument("--version", "-V", action="version", version=f"%(prog)s {__version__}")

    subparsers = parser.add_subparsers(dest="command", help="Commands")

    # Auth commands
    auth_parser = subparsers.add_parser("auth", help="Authentication commands")
    auth_subparsers = auth_parser.add_subparsers(dest="auth_command")

    auth_login = auth_subparsers.add_parser("login", help="Authenticate with API key")
    auth_login.add_argument("api_key", nargs="?", help="API key (or prompt if not provided)")
    auth_login.add_argument("--api-url", help="Custom API URL")

    auth_subparsers.add_parser("logout", help="Clear stored credentials")
    auth_subparsers.add_parser("status", help="Check authentication status")

    # Agent command
    subparsers.add_parser("agent", help="Show agent info")

    # Logs commands
    logs_parser = subparsers.add_parser("logs", help="View call logs")
    logs_subparsers = logs_parser.add_subparsers(dest="logs_command")

    # logs list (default when no subcommand)
    logs_list = logs_subparsers.add_parser("list", help="List call logs")
    logs_list.add_argument("-n", "--limit", type=int, default=20, help="Max logs to show")
    logs_list.add_argument("--offset", type=int, default=0, help="Skip N logs")
    logs_list.add_argument("--status", choices=["completed", "failed", "abandoned", "in_progress"], help="Filter by status")
    logs_list.add_argument("--json", action="store_true", help="Output as JSON")

    # logs <session_id> - show details
    logs_show = logs_subparsers.add_parser("show", help="Show session details")
    logs_show.add_argument("session_id", help="Session ID")
    logs_show.add_argument("--json", action="store_true", help="Output as JSON")

    # logs download <session_id> - download recording
    logs_download = logs_subparsers.add_parser("download", help="Download call recording")
    logs_download.add_argument("session_id", help="Session ID")
    logs_download.add_argument("-o", "--output", help="Output file path (default: recording_<id>.<format>)")

    # Backwards compatibility: logs <session_id> still works
    logs_parser.add_argument("session_id", nargs="?", help="Session ID for details (legacy)")
    logs_parser.add_argument("-n", "--limit", type=int, default=20, help="Max logs to show")
    logs_parser.add_argument("--offset", type=int, default=0, help="Skip N logs")
    logs_parser.add_argument("--status", choices=["completed", "failed", "abandoned", "in_progress"], help="Filter by status")
    logs_parser.add_argument("--json", action="store_true", help="Output as JSON")

    # Stats command
    stats_parser = subparsers.add_parser("stats", help="Show call statistics")
    stats_parser.add_argument("--json", action="store_true", help="Output as JSON")

    # Prompt commands
    prompt_parser = subparsers.add_parser("prompt", help="Manage agent prompt")
    prompt_subparsers = prompt_parser.add_subparsers(dest="prompt_command")

    prompt_subparsers.add_parser("show", help="Show current prompt")

    prompt_set = prompt_subparsers.add_parser("set", help="Set prompt from stdin or file")
    prompt_set.add_argument("-f", "--file", help="Read prompt from file")
    prompt_set.add_argument("--greeting", action="store_true", help="Update greeting instead of prompt")

    prompt_edit = prompt_subparsers.add_parser("edit", help="Edit prompt in $EDITOR")
    prompt_edit.add_argument("--greeting", action="store_true", help="Edit greeting instead of prompt")

    # Debug command
    debug_parser = subparsers.add_parser("debug", help="Stream real-time debug events")
    debug_parser.add_argument("--poll", action="store_true", help="Use HTTP polling instead of WebSocket")
    debug_parser.add_argument("-i", "--interval", type=float, default=0.5, help="Poll interval in seconds (default: 0.5, only used with --poll)")

    return parser


def main() -> int:
    parser = create_parser()
    args = parser.parse_args()

    if not args.command:
        parser.print_help()
        return 0

    if args.command == "auth":
        if args.auth_command == "login":
            return cmd_auth_login(args)
        elif args.auth_command == "logout":
            return cmd_auth_logout(args)
        elif args.auth_command == "status":
            return cmd_auth_status(args)
        else:
            parser.parse_args(["auth", "-h"])
            return 0

    elif args.command == "agent":
        return cmd_agent(args)

    elif args.command == "logs":
        if args.logs_command == "list":
            return cmd_logs_list(args)
        elif args.logs_command == "show":
            return cmd_logs_detail(args)
        elif args.logs_command == "download":
            return cmd_logs_download(args)
        elif args.session_id:
            # Backwards compatibility: vb logs <session_id>
            return cmd_logs_detail(args)
        else:
            return cmd_logs_list(args)

    elif args.command == "stats":
        return cmd_stats(args)

    elif args.command == "prompt":
        if args.prompt_command == "show":
            return cmd_prompt_show(args)
        elif args.prompt_command == "set":
            return cmd_prompt_set(args)
        elif args.prompt_command == "edit":
            return cmd_prompt_edit(args)
        else:
            parser.parse_args(["prompt", "-h"])
            return 0

    elif args.command == "debug":
        return cmd_debug(args)

    else:
        parser.print_help()
        return 0


if __name__ == "__main__":
    sys.exit(main())
