"""CLI tools for Arzule observability SDK."""

from __future__ import annotations

import argparse
import json
import os
import sys
from pathlib import Path
from typing import Any


# Configuration paths
ARZULE_CONFIG_DIR = Path.home() / ".arzule"
ARZULE_CONFIG_FILE = ARZULE_CONFIG_DIR / "config"


def load_config() -> dict[str, str]:
    """Load configuration from ~/.arzule/config."""
    config = {}
    if ARZULE_CONFIG_FILE.exists():
        try:
            for line in ARZULE_CONFIG_FILE.read_text().splitlines():
                line = line.strip()
                if not line or line.startswith("#"):
                    continue
                if "=" in line:
                    key, _, value = line.partition("=")
                    key = key.strip()
                    value = value.strip()
                    # Remove quotes
                    if (value.startswith('"') and value.endswith('"')) or \
                       (value.startswith("'") and value.endswith("'")):
                        value = value[1:-1]
                    config[key] = value
        except Exception:
            pass
    return config


def save_config(config: dict[str, str]) -> bool:
    """Save configuration to ~/.arzule/config."""
    try:
        ARZULE_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
        lines = [
            "# Arzule Configuration",
            "# Generated by: arzule configure",
            "",
        ]
        for key, value in sorted(config.items()):
            lines.append(f'{key}="{value}"')
        ARZULE_CONFIG_FILE.write_text("\n".join(lines) + "\n")
        return True
    except Exception:
        return False


def cmd_configure(args: argparse.Namespace) -> int:
    """Interactive configuration setup."""
    print("Arzule Configuration")
    print("=" * 40)
    print()
    print("Enter your Arzule credentials from https://app.arzule.com/settings")
    print("Press Enter to keep existing value, or type a new value.")
    print()

    # Load existing config
    existing = load_config()

    # Collect values
    config = {}

    # API Key
    current_key = existing.get("ARZULE_API_KEY", "")
    masked = f"...{current_key[-8:]}" if len(current_key) > 8 else current_key
    prompt = f"API Key [{masked}]: " if current_key else "API Key: "
    try:
        value = input(prompt).strip()
    except (EOFError, KeyboardInterrupt):
        print("\nConfiguration cancelled.")
        return 1
    config["ARZULE_API_KEY"] = value if value else current_key

    # Tenant ID
    current = existing.get("ARZULE_TENANT_ID", "")
    masked = f"...{current[-8:]}" if len(current) > 8 else current
    prompt = f"Tenant ID [{masked}]: " if current else "Tenant ID: "
    try:
        value = input(prompt).strip()
    except (EOFError, KeyboardInterrupt):
        print("\nConfiguration cancelled.")
        return 1
    config["ARZULE_TENANT_ID"] = value if value else current

    # Project ID
    current = existing.get("ARZULE_PROJECT_ID", "")
    masked = f"...{current[-8:]}" if len(current) > 8 else current
    prompt = f"Project ID [{masked}]: " if current else "Project ID: "
    try:
        value = input(prompt).strip()
    except (EOFError, KeyboardInterrupt):
        print("\nConfiguration cancelled.")
        return 1
    config["ARZULE_PROJECT_ID"] = value if value else current

    # Endpoint is hardcoded - no need for users to configure
    # (Can be overridden in config file for testing if needed)

    # Validate required fields
    missing = []
    for key in ["ARZULE_API_KEY", "ARZULE_TENANT_ID", "ARZULE_PROJECT_ID"]:
        if not config.get(key):
            missing.append(key)

    if missing:
        print()
        print(f"Warning: Missing required fields: {', '.join(missing)}")
        print("Traces will be saved locally to ~/.arzule/traces/ until configured.")

    # Save
    print()
    if save_config(config):
        print(f"Configuration saved to {ARZULE_CONFIG_FILE}")
        print()
        print("Next steps (choose one):")
        print()
        print("  Option A: Shell integration (recommended)")
        print("    $ arzule setup")
        print("    Then use 'claude' normally - metrics are captured automatically!")
        print()
        print("  Option B: Explicit wrapper")
        print("    $ arzule claude 'your prompt'")
        print("    Or: $ arzule-claude 'your prompt'")
        print()
        print("  Option C: Hooks only (no token metrics)")
        print("    $ arzule claude install")
        print("    Then use 'claude' normally")
        return 0
    else:
        print(f"Error: Failed to save configuration", file=sys.stderr)
        return 1


def cmd_config_show(args: argparse.Namespace) -> int:
    """Show current configuration."""
    config = load_config()

    print("Arzule Configuration")
    print("=" * 40)
    print(f"Config file: {ARZULE_CONFIG_FILE}")
    print()

    if not config:
        print("No configuration found.")
        print()
        print("Run 'arzule configure' to set up your credentials.")
        return 0

    for key, value in sorted(config.items()):
        # Mask API key
        if "KEY" in key and len(value) > 8:
            display = f"...{value[-8:]}"
        else:
            display = value
        print(f"  {key}: {display}")

    return 0


def load_trace(path: str) -> list[dict[str, Any]]:
    """Load events from a JSONL trace file."""
    events = []
    with open(path) as f:
        for line in f:
            line = line.strip()
            if line:
                events.append(json.loads(line))
    return events


def format_timeline(events: list[dict[str, Any]], show_llm: bool = True) -> str:
    """Format events as a timeline view."""
    lines = []
    
    if not events:
        return "No events found."
    
    # Header
    lines.append("=" * 80)
    lines.append(f"TRACE: {events[0].get('trace_id', 'unknown')}")
    lines.append(f"RUN:   {events[0].get('run_id', 'unknown')}")
    lines.append(f"Tenant: {events[0].get('tenant_id', 'unknown')} / Project: {events[0].get('project_id', 'unknown')}")
    lines.append("=" * 80)
    lines.append("")
    
    for e in events:
        event_type = e.get("event_type", "unknown")
        
        # Skip LLM events if not requested
        if not show_llm and "llm" in event_type:
            continue
        
        ts = e.get("ts", "")[:19].replace("T", " ")
        seq = e.get("seq", 0)
        agent = e.get("agent") or {}
        agent_role = agent.get("role", "") if agent else ""
        attrs = e.get("attrs_compact") or {}
        status = e.get("status", "ok")
        
        # Indentation and icon based on event type
        indent = ""
        icon = ""
        if "run" in event_type:
            icon = "[RUN]"
        elif "crew" in event_type:
            icon = "[CREW]"
        elif "task" in event_type:
            indent = "  "
            icon = "[TASK]"
        elif "agent" in event_type:
            indent = "    "
            icon = "[AGENT]"
        elif "tool" in event_type:
            indent = "      "
            icon = "[TOOL]"
        elif "llm" in event_type:
            indent = "      "
            icon = "[LLM]"
        elif "handoff" in event_type:
            indent = "    "
            icon = "[HANDOFF]"
        else:
            icon = "[EVENT]"
        
        # Direction indicator
        direction = "   "
        if "start" in event_type:
            direction = "-->"
        elif "complete" in event_type or "end" in event_type:
            direction = "<--"
        elif "error" in event_type or "failed" in event_type:
            direction = "XXX"
        elif "ack" in event_type:
            direction = "<->"
        
        # Status indicator for errors
        status_mark = ""
        if status == "error":
            status_mark = " [ERROR]"
        
        # Build description
        desc_parts = []
        if agent_role:
            desc_parts.append(agent_role)
        
        tool_name = attrs.get("tool_name")
        if tool_name:
            desc_parts.append(f"tool={tool_name}")
        
        task_id = e.get("task_id")
        if task_id:
            desc_parts.append(f"task={task_id[:8]}...")
        
        # Event type suffix
        event_suffix = event_type.split(".")[-1]
        if desc_parts:
            desc = f"{': '.join(desc_parts)} ({event_suffix})"
        else:
            desc = event_suffix
        
        line = f"{seq:2d}. {ts} {indent}{icon:10s} {direction} {desc}{status_mark}"
        lines.append(line)
    
    lines.append("")
    lines.append("=" * 80)
    
    # Summary
    event_counts: dict[str, int] = {}
    for e in events:
        etype = e.get("event_type", "unknown").split(".")[0]
        event_counts[etype] = event_counts.get(etype, 0) + 1
    
    lines.append(f"Total events: {len(events)}")
    lines.append(f"Breakdown: {', '.join(f'{k}={v}' for k, v in sorted(event_counts.items()))}")
    
    return "\n".join(lines)


def format_table(events: list[dict[str, Any]]) -> str:
    """Format events as a compact table."""
    lines = []
    
    # Header
    lines.append(f"{'Seq':>3} {'Event Type':<25} {'Agent':<12} {'Tool':<20} {'Status':<6}")
    lines.append("-" * 70)
    
    for e in events:
        seq = e.get("seq", 0)
        event_type = e.get("event_type", "unknown")
        agent = e.get("agent") or {}
        agent_role = agent.get("role", "-") if agent else "-"
        attrs = e.get("attrs_compact") or {}
        tool_name = attrs.get("tool_name", "-")
        status = e.get("status", "ok")
        
        lines.append(f"{seq:>3} {event_type:<25} {agent_role:<12} {tool_name:<20} {status:<6}")
    
    return "\n".join(lines)


def format_json(events: list[dict[str, Any]], pretty: bool = True) -> str:
    """Format events as JSON."""
    if pretty:
        return json.dumps(events, indent=2)
    return json.dumps(events)


def format_tree(events: list[dict[str, Any]]) -> str:
    """Format events as a tree based on span hierarchy."""
    lines = []
    
    if not events:
        return "No events found."
    
    # Build span hierarchy
    span_to_event: dict[str, dict] = {}
    children: dict[str, list[str]] = {}
    roots: list[str] = []
    
    for e in events:
        span_id = e.get("span_id")
        parent_id = e.get("parent_span_id")
        
        if span_id:
            span_to_event[span_id] = e
            if parent_id:
                if parent_id not in children:
                    children[parent_id] = []
                children[parent_id].append(span_id)
            else:
                roots.append(span_id)
    
    def render_span(span_id: str, depth: int = 0) -> None:
        e = span_to_event.get(span_id)
        if not e:
            return
        
        event_type = e.get("event_type", "unknown")
        agent = e.get("agent") or {}
        agent_role = agent.get("role", "") if agent else ""
        attrs = e.get("attrs_compact") or {}
        tool_name = attrs.get("tool_name", "")
        
        prefix = "  " * depth
        
        desc = event_type
        if agent_role:
            desc += f" [{agent_role}]"
        if tool_name:
            desc += f" ({tool_name})"
        
        lines.append(f"{prefix}- {desc}")
        
        for child_id in children.get(span_id, []):
            render_span(child_id, depth + 1)
    
    lines.append("Span Tree:")
    lines.append("-" * 40)
    for root_id in roots:
        render_span(root_id)
    
    return "\n".join(lines)


def cmd_view(args: argparse.Namespace) -> int:
    """View a trace file."""
    try:
        events = load_trace(args.file)
    except FileNotFoundError:
        print(f"Error: File not found: {args.file}", file=sys.stderr)
        return 1
    except json.JSONDecodeError as e:
        print(f"Error: Invalid JSON in trace file: {e}", file=sys.stderr)
        return 1
    
    if args.format == "timeline":
        output = format_timeline(events, show_llm=not args.no_llm)
    elif args.format == "table":
        output = format_table(events)
    elif args.format == "json":
        output = format_json(events, pretty=not args.compact)
    elif args.format == "tree":
        output = format_tree(events)
    else:
        output = format_timeline(events, show_llm=not args.no_llm)
    
    print(output)
    return 0


def cmd_stats(args: argparse.Namespace) -> int:
    """Show statistics for a trace file."""
    try:
        events = load_trace(args.file)
    except FileNotFoundError:
        print(f"Error: File not found: {args.file}", file=sys.stderr)
        return 1
    
    if not events:
        print("No events found.")
        return 0
    
    # Basic stats
    print(f"Trace ID: {events[0].get('trace_id', 'unknown')}")
    print(f"Run ID: {events[0].get('run_id', 'unknown')}")
    print(f"Total events: {len(events)}")
    print()
    
    # Time range
    timestamps = [e.get("ts", "") for e in events if e.get("ts")]
    if timestamps:
        print(f"Start: {timestamps[0]}")
        print(f"End: {timestamps[-1]}")
    print()
    
    # Event type breakdown
    event_counts: dict[str, int] = {}
    for e in events:
        etype = e.get("event_type", "unknown")
        event_counts[etype] = event_counts.get(etype, 0) + 1
    
    print("Event counts:")
    for etype, count in sorted(event_counts.items()):
        print(f"  {etype}: {count}")
    print()
    
    # Agent breakdown
    agents: set[str] = set()
    for e in events:
        agent = e.get("agent") or {}
        role = agent.get("role")
        if role:
            agents.add(role)
    
    if agents:
        print(f"Agents: {', '.join(sorted(agents))}")
    
    # Error count
    errors = [e for e in events if e.get("status") == "error"]
    if errors:
        print(f"Errors: {len(errors)}")
        for err in errors:
            print(f"  - {err.get('event_type')}: {err.get('summary', '')[:50]}")
    
    return 0


def cmd_claude_install(args: argparse.Namespace) -> int:
    """Install Arzule hooks into Claude Code settings."""
    try:
        from .claude.install import install_claude_code, get_installation_status
    except ImportError as e:
        print(f"Error: Claude Code module not available: {e}", file=sys.stderr)
        return 1

    # Check if configuration exists
    config = load_config()
    has_config = all([
        config.get("ARZULE_API_KEY"),
        config.get("ARZULE_TENANT_ID"),
        config.get("ARZULE_PROJECT_ID"),
    ])

    # Determine settings path based on --project flag
    settings_path = None
    if args.project:
        settings_path = Path(args.project) / ".claude" / "settings.json"

    try:
        success = install_claude_code(settings_path=settings_path)
        if success:
            status = get_installation_status(settings_path)
            print(f"Arzule hooks installed to: {status.get('settings_path', 'settings.json')}")
            print()

            if has_config:
                print("Configuration found at ~/.arzule/config")
                print()
                print("You're all set! Start Claude Code and traces will appear in your dashboard.")
            else:
                print("No configuration found.")
                print()
                print("Next step: Run 'arzule configure' to set up your credentials.")
                print("Or traces will be saved locally to ~/.arzule/traces/")
            return 0
        else:
            print("Installation failed.", file=sys.stderr)
            return 1
    except Exception as e:
        print(f"Error during installation: {e}", file=sys.stderr)
        return 1


def cmd_claude_uninstall(args: argparse.Namespace) -> int:
    """Remove Arzule hooks from Claude Code settings."""
    try:
        from .claude.install import uninstall_claude_code
    except ImportError as e:
        print(f"Error: Claude Code module not available: {e}", file=sys.stderr)
        return 1

    from pathlib import Path

    # Determine settings path based on --project flag
    settings_path = None
    if args.project:
        settings_path = Path(args.project) / ".claude" / "settings.json"

    try:
        success = uninstall_claude_code(settings_path=settings_path)
        if success:
            print("Successfully removed Arzule hooks from Claude Code settings.")
            return 0
        else:
            print("Uninstallation failed.", file=sys.stderr)
            return 1
    except Exception as e:
        print(f"Error during uninstallation: {e}", file=sys.stderr)
        return 1


def cmd_setup(args: argparse.Namespace) -> int:
    """Set up shell environment for automatic Claude Code instrumentation."""
    
    # Determine shell and config file
    shell = os.environ.get("SHELL", "/bin/bash")
    shell_name = Path(shell).name
    
    if shell_name == "zsh":
        rc_file = Path.home() / ".zshrc"
    elif shell_name == "bash":
        # Check for .bash_profile on macOS, .bashrc on Linux
        bash_profile = Path.home() / ".bash_profile"
        bashrc = Path.home() / ".bashrc"
        rc_file = bash_profile if bash_profile.exists() else bashrc
    elif shell_name == "fish":
        rc_file = Path.home() / ".config" / "fish" / "config.fish"
    else:
        print(f"Unsupported shell: {shell_name}", file=sys.stderr)
        print("Supported shells: zsh, bash, fish")
        print()
        print("You can manually add these environment variables to your shell config:")
        _print_env_vars()
        return 1
    
    # Load Arzule config
    config = load_config()
    api_key = config.get("ARZULE_API_KEY")
    
    if not api_key:
        print("No API key found. Run 'arzule configure' first.", file=sys.stderr)
        return 1
    
    # Build OTel endpoint
    ingest_url = config.get("ARZULE_INGEST_URL", "https://ingest.arzule.dev")
    if ingest_url.endswith("/ingest"):
        otel_endpoint = ingest_url.replace("/ingest", "/otel")
    else:
        otel_endpoint = ingest_url.rstrip("/") + "/otel"
    
    # Check if already installed
    marker = "# Arzule Claude Code instrumentation"
    if rc_file.exists():
        existing_content = rc_file.read_text()
        if marker in existing_content:
            if args.force:
                # Remove existing block
                lines = existing_content.split("\n")
                new_lines = []
                skip = False
                for line in lines:
                    if line.strip() == marker:
                        skip = True
                    elif skip and line.strip() == "# End Arzule":
                        skip = False
                        continue
                    if not skip:
                        new_lines.append(line)
                existing_content = "\n".join(new_lines)
            else:
                print(f"Arzule instrumentation already installed in {rc_file}")
                print("Use --force to reinstall.")
                return 0
    else:
        existing_content = ""
    
    # Build the shell block
    if shell_name == "fish":
        shell_block = f"""
{marker}
set -gx CLAUDE_CODE_ENABLE_TELEMETRY 1
set -gx OTEL_EXPORTER_OTLP_ENDPOINT "{otel_endpoint}"
set -gx OTEL_EXPORTER_OTLP_HEADERS "Authorization=Bearer {api_key}"
set -gx OTEL_EXPORTER_OTLP_PROTOCOL "http/json"
set -gx OTEL_TRACES_EXPORTER "otlp"
set -gx OTEL_SERVICE_NAME "claude-code"
# End Arzule
"""
    else:
        shell_block = f"""
{marker}
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_EXPORTER_OTLP_ENDPOINT="{otel_endpoint}"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer {api_key}"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/json"
export OTEL_TRACES_EXPORTER="otlp"
export OTEL_SERVICE_NAME="claude-code"
# End Arzule
"""
    
    # Write to RC file
    try:
        rc_file.parent.mkdir(parents=True, exist_ok=True)
        with open(rc_file, "a") as f:
            f.write(shell_block)
        
        print(f"Added Arzule instrumentation to {rc_file}")
        print()
        print("To activate now, run:")
        print(f"  source {rc_file}")
        print()
        print("Or open a new terminal window.")
        print()
        print("Then just use 'claude' normally - all traces will be captured!")
        return 0
    except Exception as e:
        print(f"Error writing to {rc_file}: {e}", file=sys.stderr)
        return 1


def cmd_setup_remove(args: argparse.Namespace) -> int:
    """Remove Arzule shell instrumentation."""
    
    shell = os.environ.get("SHELL", "/bin/bash")
    shell_name = Path(shell).name
    
    if shell_name == "zsh":
        rc_file = Path.home() / ".zshrc"
    elif shell_name == "bash":
        bash_profile = Path.home() / ".bash_profile"
        bashrc = Path.home() / ".bashrc"
        rc_file = bash_profile if bash_profile.exists() else bashrc
    elif shell_name == "fish":
        rc_file = Path.home() / ".config" / "fish" / "config.fish"
    else:
        print(f"Unsupported shell: {shell_name}", file=sys.stderr)
        return 1
    
    if not rc_file.exists():
        print(f"Shell config not found: {rc_file}")
        return 0
    
    marker = "# Arzule Claude Code instrumentation"
    content = rc_file.read_text()
    
    if marker not in content:
        print("Arzule instrumentation not found in shell config.")
        return 0
    
    # Remove the block
    lines = content.split("\n")
    new_lines = []
    skip = False
    for line in lines:
        if line.strip() == marker:
            skip = True
            continue
        elif skip and line.strip() == "# End Arzule":
            skip = False
            continue
        if not skip:
            new_lines.append(line)
    
    # Write back
    try:
        rc_file.write_text("\n".join(new_lines))
        print(f"Removed Arzule instrumentation from {rc_file}")
        print()
        print("Restart your terminal or run:")
        print(f"  source {rc_file}")
        return 0
    except Exception as e:
        print(f"Error writing to {rc_file}: {e}", file=sys.stderr)
        return 1


def cmd_setup_status(args: argparse.Namespace) -> int:
    """Check if shell instrumentation is active."""
    
    # Check environment variables
    otel_enabled = os.environ.get("CLAUDE_CODE_ENABLE_TELEMETRY") == "1"
    otel_endpoint = os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT", "")
    
    print("Shell Instrumentation Status")
    print("=" * 40)
    
    if otel_enabled and "arzule" in otel_endpoint.lower():
        print("Status: ACTIVE")
        print(f"OTel Endpoint: {otel_endpoint}")
        print()
        print("All 'claude' commands will send metrics to Arzule.")
    else:
        print("Status: NOT ACTIVE")
        print()
        print("To enable, run: arzule setup")
        
        # Check if it's in the RC file but not sourced
        shell = os.environ.get("SHELL", "/bin/bash")
        shell_name = Path(shell).name
        
        if shell_name == "zsh":
            rc_file = Path.home() / ".zshrc"
        elif shell_name == "bash":
            rc_file = Path.home() / ".bash_profile"
            if not rc_file.exists():
                rc_file = Path.home() / ".bashrc"
        else:
            rc_file = None
        
        if rc_file and rc_file.exists():
            if "# Arzule Claude Code instrumentation" in rc_file.read_text():
                print()
                print(f"Note: Instrumentation is in {rc_file} but not active.")
                print(f"Run: source {rc_file}")
    
    return 0


def _print_env_vars():
    """Print environment variables for manual setup."""
    config = load_config()
    api_key = config.get("ARZULE_API_KEY", "YOUR_API_KEY")
    ingest_url = config.get("ARZULE_INGEST_URL", "https://ingest.arzule.dev")
    
    if ingest_url.endswith("/ingest"):
        otel_endpoint = ingest_url.replace("/ingest", "/otel")
    else:
        otel_endpoint = ingest_url.rstrip("/") + "/otel"
    
    print("export CLAUDE_CODE_ENABLE_TELEMETRY=1")
    print(f'export OTEL_EXPORTER_OTLP_ENDPOINT="{otel_endpoint}"')
    print(f'export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer {api_key}"')
    print('export OTEL_EXPORTER_OTLP_PROTOCOL="http/json"')
    print('export OTEL_TRACES_EXPORTER="otlp"')
    print('export OTEL_SERVICE_NAME="claude-code"')


def cmd_claude_run(args: argparse.Namespace) -> int:
    """Run Claude Code with Arzule instrumentation (passthrough to arzule-claude)."""
    try:
        from .claude.wrapper import run_claude_with_otel
    except ImportError as e:
        print(f"Error: Claude wrapper not available: {e}", file=sys.stderr)
        return 1
    
    # The wrapper will handle everything and exec into claude
    run_claude_with_otel()
    # If we get here, exec failed - run_claude_with_otel doesn't return on success
    return 1


def cmd_claude_status(args: argparse.Namespace) -> int:
    """Check Arzule hook installation status for Claude Code."""
    try:
        from .claude.install import get_installation_status, print_installation_instructions
    except ImportError as e:
        print(f"Error: Claude Code module not available: {e}", file=sys.stderr)
        return 1

    from pathlib import Path

    # Determine settings path based on --project flag
    settings_path = None
    if args.project:
        settings_path = Path(args.project) / ".claude" / "settings.json"

    try:
        status = get_installation_status(settings_path)

        print("Claude Code Integration Status")
        print("=" * 40)
        print(f"Installed: {'Yes' if status.get('installed') else 'No'}")
        print(f"Settings Path: {status.get('settings_path', 'N/A')}")

        if status.get('installed'):
            events = status.get('events', {})
            installed_events = [k for k, v in events.items() if v]
            print(f"Hooks installed: {len(installed_events)}")
            for event in installed_events:
                print(f"  - {event}")
        else:
            print("\nTo install, run: arzule claude install")

        # Configuration check
        config = load_config()
        api_key = config.get("ARZULE_API_KEY") or os.environ.get("ARZULE_API_KEY")
        tenant_id = config.get("ARZULE_TENANT_ID") or os.environ.get("ARZULE_TENANT_ID")
        project_id = config.get("ARZULE_PROJECT_ID") or os.environ.get("ARZULE_PROJECT_ID")

        print(f"\nConfiguration ({ARZULE_CONFIG_FILE}):")
        print(f"  ARZULE_API_KEY: {'Set' if api_key else 'Not set'}")
        print(f"  ARZULE_TENANT_ID: {'Set' if tenant_id else 'Not set'}")
        print(f"  ARZULE_PROJECT_ID: {'Set' if project_id else 'Not set'}")

        if all([api_key, tenant_id, project_id]):
            print("\n  Ready! Traces will be sent to your Arzule dashboard.")
        else:
            print("\n  Run 'arzule configure' to set up credentials.")
            print("  Or traces will save locally to ~/.arzule/traces/")

        return 0
    except Exception as e:
        print(f"Error checking status: {e}", file=sys.stderr)
        return 1


def main() -> int:
    """Main CLI entrypoint."""
    parser = argparse.ArgumentParser(
        prog="arzule",
        description="Arzule observability SDK - trace multi-agent AI systems",
    )
    subparsers = parser.add_subparsers(dest="command", help="Commands")

    # === Configure command (top-level for easy access) ===
    configure_parser = subparsers.add_parser(
        "configure",
        help="Configure Arzule credentials (interactive setup)"
    )
    configure_parser.set_defaults(func=cmd_configure)

    # === Config show command ===
    config_parser = subparsers.add_parser(
        "config",
        help="Show current configuration"
    )
    config_parser.set_defaults(func=cmd_config_show)

    # === Setup command (shell integration) ===
    setup_parser = subparsers.add_parser(
        "setup",
        help="Set up shell for automatic Claude instrumentation"
    )
    setup_parser.add_argument(
        "--force", "-f",
        action="store_true",
        help="Reinstall even if already installed"
    )
    setup_parser.set_defaults(func=cmd_setup)

    # === Setup remove command ===
    setup_remove_parser = subparsers.add_parser(
        "setup-remove",
        help="Remove shell instrumentation"
    )
    setup_remove_parser.set_defaults(func=cmd_setup_remove)

    # === Setup status command ===
    setup_status_parser = subparsers.add_parser(
        "setup-status",
        help="Check if shell instrumentation is active"
    )
    setup_status_parser.set_defaults(func=cmd_setup_status)

    # === Claude Code commands ===
    # Special handling: 'arzule claude' without subcommand runs claude with instrumentation
    claude_parser = subparsers.add_parser(
        "claude", 
        help="Claude Code integration (or run: arzule claude 'prompt')"
    )
    claude_subparsers = claude_parser.add_subparsers(dest="claude_command", help="Claude commands")

    # claude install
    claude_install = claude_subparsers.add_parser("install", help="Install Arzule hooks")
    claude_install.add_argument(
        "--project", "-p",
        metavar="PATH",
        help="Install to project-level settings (.claude/settings.json)",
    )
    claude_install.set_defaults(func=cmd_claude_install)

    # claude uninstall
    claude_uninstall = claude_subparsers.add_parser("uninstall", help="Remove Arzule hooks")
    claude_uninstall.add_argument(
        "--project", "-p",
        metavar="PATH",
        help="Remove from project-level settings",
    )
    claude_uninstall.set_defaults(func=cmd_claude_uninstall)

    # claude status
    claude_status = claude_subparsers.add_parser("status", help="Check installation status")
    claude_status.add_argument(
        "--project", "-p",
        metavar="PATH",
        help="Check project-level settings",
    )
    claude_status.set_defaults(func=cmd_claude_status)

    # === View commands ===
    # view command
    view_parser = subparsers.add_parser("view", help="View a trace file")
    view_parser.add_argument("file", help="Path to the JSONL trace file")
    view_parser.add_argument(
        "-f", "--format",
        choices=["timeline", "table", "json", "tree"],
        default="timeline",
        help="Output format (default: timeline)",
    )
    view_parser.add_argument(
        "--no-llm",
        action="store_true",
        help="Hide LLM call events",
    )
    view_parser.add_argument(
        "--compact",
        action="store_true",
        help="Compact JSON output (no indentation)",
    )
    view_parser.set_defaults(func=cmd_view)

    # stats command
    stats_parser = subparsers.add_parser("stats", help="Show trace statistics")
    stats_parser.add_argument("file", help="Path to the JSONL trace file")
    stats_parser.set_defaults(func=cmd_stats)

    # Check for 'arzule claude <something>' where <something> is not a subcommand
    # In that case, pass through to the claude wrapper
    if len(sys.argv) >= 3 and sys.argv[1] == "claude":
        # Check if second arg is a known subcommand
        known_subcommands = {"install", "uninstall", "status"}
        if sys.argv[2] not in known_subcommands:
            # It's a passthrough - run claude with remaining args
            # Rewrite sys.argv for the wrapper
            sys.argv = ["arzule-claude"] + sys.argv[2:]
            return cmd_claude_run(argparse.Namespace())

    args = parser.parse_args()

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

    # Handle claude subcommand
    if args.command == "claude":
        if not getattr(args, 'claude_command', None):
            claude_parser.print_help()
            return 0
        return args.func(args)

    return args.func(args)


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

