import typer
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from pathlib import Path
import json

app = typer.Typer(
    name="direction",
    help="Project-aware coding assistant powered by vector search.",
    add_completion=False
)

console = Console()

CONFIG_DIR = Path(".vectormind")
CONFIG_FILE = CONFIG_DIR / "config.json"

DEFAULT_CONFIG = {
    "embedding_model": "text-embedding-3-small",
    "default_model": "gpt-4o-mini",
    "fallback_model": "gpt-4o",
    "chunk_size": 200,
    "chunk_overlap": 20,
    "top_k": 5,
    "extensions": [
        ".py", ".js", ".ts", ".jsx", ".tsx",
        ".java", ".cpp", ".c", ".h", ".cs",
        ".go", ".rs", ".rb", ".php",
        ".md", ".txt", ".json", ".yaml", ".yml",
        ".toml", ".env.example"
    ],
    "exclude_dirs": [
        ".vectormind", ".git", "node_modules",
        "__pycache__", ".venv", "venv",
        "dist", "build", ".next"
    ]
}


def load_config() -> dict:
    if CONFIG_FILE.exists():
        with open(CONFIG_FILE) as f:
            return json.load(f)
    return DEFAULT_CONFIG


def ensure_initialized():
    if not CONFIG_DIR.exists():
        console.print("[red]Not initialized. Run `direction init` first.[/red]")
        raise typer.Exit(1)


@app.command()
def init(
    force: bool = typer.Option(False, "--force", "-f", help="Re-initialize existing project")
):
    """Initialize Direction for this project and run first full index."""
    if CONFIG_DIR.exists() and not force:
        console.print("[yellow]Already initialized. Use --force to re-initialize.[/yellow]")
        raise typer.Exit()

    console.print(Panel("[bold green]Initializing Direction...[/bold green]"))

    # Create .vectormind directory structure
    CONFIG_DIR.mkdir(exist_ok=True)
    (CONFIG_DIR / "chroma").mkdir(exist_ok=True)

    # Write default config
    with open(CONFIG_FILE, "w") as f:
        json.dump(DEFAULT_CONFIG, f, indent=2)

    # Write .gitignore suggestion
    gitignore = CONFIG_DIR / ".gitignore"
    gitignore.write_text("# Uncomment to exclude Direction DB from git\n# chroma/\n# analytics.db\n")

    console.print("[green]✓[/green] Created .vectormind/")
    console.print("[green]✓[/green] Written default config")

    # Trigger first index
    console.print("\n[bold]Running first index...[/bold]")
    _run_index()


@app.command()
def update(
    path: str = typer.Argument(".", help="Path to re-index (default: entire project)")
):
    """Re-index changed files. Run after editing code or on git commit."""
    ensure_initialized()
    console.print(Panel("[bold blue]Updating index...[/bold blue]"))
    _run_index(path=path, incremental=True)


@app.command()
def query(
    question: str = typer.Argument(..., help="Your coding question"),
    top_k: int = typer.Option(None, "--top-k", "-k", help="Number of chunks to retrieve"),
    model: str = typer.Option(None, "--model", "-m", help="Override model (gpt-4o-mini or gpt-4o)"),
    show_sources: bool = typer.Option(False, "--sources", "-s", help="Show retrieved source chunks")
):
    """Ask a question about your codebase."""
    ensure_initialized()

    config = load_config()
    top_k = top_k or config["top_k"]
    model = model or config["default_model"]

    console.print(f"\n[bold]Query:[/bold] {question}")
    console.print(f"[dim]Model: {model} | Retrieving top {top_k} chunks[/dim]\n")

    from direction.query import run_query
    run_query(question=question, top_k=top_k, model=model, show_sources=show_sources, config=config)


@app.command()
def dashboard(
    port: int = typer.Option(8000, "--port", "-p", help="Port to run dashboard on"),
    host: str = typer.Option("127.0.0.1", "--host", help="Host to bind to")
):
    """Launch the local analytics dashboard."""
    ensure_initialized()

    console.print(Panel(f"[bold green]Launching dashboard at http://{host}:{port}[/bold green]"))
    console.print("[dim]Press Ctrl+C to stop[/dim]\n")

    import uvicorn
    from direction.dashboard import app as dashboard_app
    uvicorn.run(dashboard_app, host=host, port=port)


@app.command()
def status():
    """Show index health, DB stats, and recent analytics."""
    ensure_initialized()

    config = load_config()

    console.print(Panel("[bold]Direction Status[/bold]"))

    # Config table
    table = Table(show_header=False, box=None, padding=(0, 2))
    table.add_row("[dim]Embedding model[/dim]", config["embedding_model"])
    table.add_row("[dim]Default model[/dim]", config["default_model"])
    table.add_row("[dim]Fallback model[/dim]", config["fallback_model"])
    table.add_row("[dim]Chunk size[/dim]", str(config["chunk_size"]))
    table.add_row("[dim]Top K retrieval[/dim]", str(config["top_k"]))
    console.print(table)

    # DB stats
    try:
        from direction.db import get_stats
        stats = get_stats()
        console.print(f"\n[green]✓[/green] Indexed chunks: [bold]{stats['total_chunks']}[/bold]")
        console.print(f"[green]✓[/green] Indexed files:  [bold]{stats['total_files']}[/bold]")
        console.print(f"[dim]Last indexed: {stats['last_indexed']}[/dim]")
    except Exception as e:
        console.print(f"[yellow]DB not yet populated. Run `direction init`.[/yellow]")

    # Analytics summary
    try:
        from direction.analytics import get_summary
        summary = get_summary()
        console.print(f"\n[bold]Analytics:[/bold]")
        console.print(f"  Total queries:     {summary['total_queries']}")
        console.print(f"  Total tokens used: {summary['total_tokens']}")
        console.print(f"  Total cost:        ${summary['total_cost']:.4f}")
        console.print(f"  Avg response time: {summary['avg_response_time']:.2f}s")
    except Exception:
        console.print("\n[dim]No analytics yet. Run a query first.[/dim]")


@app.command()
def config(
    key: str = typer.Argument(None, help="Config key to get or set"),
    value: str = typer.Argument(None, help="Value to set")
):
    """View or update Direction configuration."""
    ensure_initialized()

    cfg = load_config()

    if key is None:
        # Print all config
        console.print(Panel("[bold]Current Configuration[/bold]"))
        for k, v in cfg.items():
            console.print(f"  [dim]{k}[/dim]: {v}")
        return

    if value is None:
        # Get single key
        if key in cfg:
            console.print(f"{key}: {cfg[key]}")
        else:
            console.print(f"[red]Unknown key: {key}[/red]")
        return

    # Set key
    if key not in cfg:
        console.print(f"[red]Unknown key: {key}[/red]")
        raise typer.Exit(1)

    # Type coerce
    original = cfg[key]
    if isinstance(original, int):
        cfg[key] = int(value)
    elif isinstance(original, bool):
        cfg[key] = value.lower() in ("true", "1", "yes")
    else:
        cfg[key] = value

    with open(CONFIG_FILE, "w") as f:
        json.dump(cfg, f, indent=2)

    console.print(f"[green]✓[/green] {key} = {cfg[key]}")


def _run_index(path: str = ".", incremental: bool = False):
    """Internal: trigger indexer."""
    try:
        from direction.indexer import index_project
        config = load_config()
        stats = index_project(root=path, config=config, incremental=incremental)
        console.print(f"[green]✓[/green] Indexed [bold]{stats['files']}[/bold] files, [bold]{stats['chunks']}[/bold] chunks")
        if incremental:
            console.print(f"[dim]  Updated: {stats['updated']} | Skipped: {stats['skipped']}[/dim]")
    except ImportError:
        console.print("[yellow]Indexer not yet implemented. Build direction/indexer.py next.[/yellow]")
    except Exception as e:
        console.print(f"[red]Indexing error: {e}[/red]")
        raise typer.Exit(1)


if __name__ == "__main__":
    app()