"""
groknroll CLI - Main entry point

The Ultimate CLI Coding Agent with unlimited context.
"""

import sys
from pathlib import Path
from typing import Optional

import click
from rich.console import Console
from rich.markdown import Markdown
from rich.panel import Panel
from rich.progress import Progress, SpinnerColumn, TextColumn
from rich.table import Table

from groknroll import __version__
from groknroll.core.agent import GroknrollAgent
from groknroll.cli.agent_commands import agent
from groknroll.cli.madace_commands import madace
from groknroll.cli.rlm_commands import rlm
from groknroll.cli.oracle_commands import oracle

console = Console()


def _run_interactive(task: str):
    """Run a single task with the build agent"""
    project_path = Path.cwd()

    try:
        with console.status("[bold cyan]Working...") as status:
            groknroll_agent = GroknrollAgent(project_path)
            response = groknroll_agent.chat(task)

        console.print()
        console.print(
            Panel(
                Markdown(response),
                title="[bold cyan]groknroll[/bold cyan]",
                border_style="cyan",
            )
        )

    except Exception as e:
        console.print(f"[bold red]Error:[/bold red] {e}")
        sys.exit(1)


def _run_interactive_repl():
    """Run interactive REPL session using NativeREPL"""
    from groknroll.repl import NativeREPL, REPLConfig

    project_path = Path.cwd()

    try:
        # Create config
        config = REPLConfig(
            model="gpt-4o-mini",
            stream_responses=True,
            auto_save=True,
            default_agent="build",
        )

        # Create and run REPL
        repl = NativeREPL(project_path=project_path, config=config)
        repl.run()

    except Exception as e:
        console.print(f"[bold red]Error:[/bold red] {e}")
        sys.exit(1)


@click.group(invoke_without_command=True)
@click.option("--version", is_flag=True, help="Show version")
@click.pass_context
def main(ctx, version):
    """
    🎸 groknroll - The Ultimate CLI Coding Agent

    Local, unlimited context, autonomous coding assistant.

    Run without arguments to start interactive mode.
    Use --help to see all commands.
    """
    if version:
        console.print(f"[bold cyan]groknroll[/bold cyan] version {__version__}")
        return

    if ctx.invoked_subcommand is None:
        # No subcommand - launch interactive REPL
        _run_interactive_repl()


@main.command()
@click.option("--path", type=click.Path(exists=True), help="Project path")
def init(path: Optional[str]):
    """Initialize groknroll for a project"""
    project_path = Path(path) if path else Path.cwd()

    with Progress(
        SpinnerColumn(), TextColumn("[progress.description]{task.description}"), console=console
    ) as progress:
        task = progress.add_task("Initializing groknroll...", total=None)

        try:
            agent = GroknrollAgent(project_path)
            stats = agent.reindex_project()

            progress.update(task, completed=True)

            # Show results
            console.print()
            console.print(
                Panel.fit(
                    f"[bold green]✓ Project initialized![/bold green]\n\n"
                    f"[cyan]Files indexed:[/cyan] {stats['indexed']}\n"
                    f"[cyan]Lines of code:[/cyan] {stats['total_lines']:,}\n"
                    f"[cyan]Files skipped:[/cyan] {stats['skipped']}",
                    title="[bold]groknroll[/bold]",
                    border_style="green",
                )
            )

        except Exception as e:
            console.print(f"[bold red]Error:[/bold red] {e}")
            sys.exit(1)


@main.command()
@click.argument("message", nargs=-1, required=True)
@click.option("--path", type=click.Path(exists=True), help="Project path")
@click.option(
    "--agent",
    default="build",
    help="Agent to use (build/plan/custom)",
    show_default=True,
)
def chat(message: tuple, path: Optional[str], agent: str):
    """Chat with groknroll about your code"""
    project_path = Path(path) if path else Path.cwd()
    message_str = " ".join(message)

    try:
        with console.status(f"[bold cyan]Thinking ({agent} agent)...") as status:
            groknroll_agent = GroknrollAgent(project_path)
            response = groknroll_agent.chat(message_str)

        # Display response
        console.print()
        console.print(
            Panel(
                Markdown(response),
                title=f"[bold cyan]groknroll ({agent})[/bold cyan]",
                border_style="cyan",
            )
        )

    except Exception as e:
        console.print(f"[bold red]Error:[/bold red] {e}")
        sys.exit(1)


@main.command()
@click.option("--path", type=click.Path(exists=True), help="Project path")
@click.option("--detailed", is_flag=True, help="Detailed analysis")
def analyze(path: Optional[str], detailed: bool):
    """Analyze project codebase"""
    project_path = Path(path) if path else Path.cwd()

    try:
        with console.status("[bold cyan]Analyzing project...") as status:
            agent = GroknrollAgent(project_path)
            results = agent.analyze_project(detailed=detailed)

        # Display results
        console.print()
        console.print(
            Panel.fit(
                Markdown(results.get("analysis", "No analysis available")),
                title="[bold cyan]Project Analysis[/bold cyan]",
                border_style="cyan",
            )
        )

        # Show metrics
        metrics = results.get("metrics", {})
        console.print(
            f"\n[dim]Analysis completed in {metrics.get('time', 0):.1f}s "
            f"(cost: ${metrics.get('cost', 0):.4f})[/dim]"
        )

    except Exception as e:
        console.print(f"[bold red]Error:[/bold red] {e}")
        sys.exit(1)


@main.command()
@click.argument("file_path", type=click.Path(exists=True), required=False)
@click.option(
    "--type",
    "analysis_type",
    default="review",
    type=click.Choice(["review", "security", "complexity", "explain"]),
    help="Analysis type",
)
@click.option("--path", type=click.Path(exists=True), help="Project path")
def review(file_path: str | None, analysis_type: str, path: str | None):
    """Review a code file or entire codebase (default: entire codebase)"""
    project_path = Path(path) if path else Path.cwd()

    try:
        if file_path:
            # Review specific file
            file_path = Path(file_path)
            with console.status(f"[bold cyan]Analyzing {file_path.name}...") as status:
                agent = GroknrollAgent(file_path.parent)
                results = agent.analyze_code(file_path=file_path, analysis_type=analysis_type)

            # Display results
            console.print()
            console.print(
                Panel(
                    Markdown(results.get("analysis", "No analysis available")),
                    title=f"[bold cyan]{analysis_type.title()}: {file_path.name}[/bold cyan]",
                    border_style="cyan",
                )
            )
        else:
            # Review entire codebase
            with console.status("[bold cyan]Analyzing entire codebase...") as status:
                agent = GroknrollAgent(project_path)
                results = agent.analyze_project(detailed=True)

            # Display results
            console.print()
            console.print(
                Panel.fit(
                    Markdown(results.get("analysis", "No analysis available")),
                    title=f"[bold cyan]Codebase {analysis_type.title()}[/bold cyan]",
                    border_style="cyan",
                )
            )

            # Show metrics
            metrics = results.get("metrics", {})
            console.print(
                f"\n[dim]Analysis completed in {metrics.get('time', 0):.1f}s "
                f"(cost: ${metrics.get('cost', 0):.4f})[/dim]"
            )

    except Exception as e:
        console.print(f"[bold red]Error:[/bold red] {e}")
        sys.exit(1)


@main.command()
@click.argument("query")
@click.option("--path", type=click.Path(exists=True), help="Project path")
@click.option("--language", help="Filter by language")
def search(query: str, path: Optional[str], language: Optional[str]):
    """Search codebase"""
    project_path = Path(path) if path else Path.cwd()

    try:
        agent = GroknrollAgent(project_path)
        results = agent.search_code(query, language)

        if not results:
            console.print(f"[yellow]No files found matching '{query}'[/yellow]")
            return

        # Display results in table
        table = Table(title=f"Search Results: '{query}'", show_header=True)
        table.add_column("File", style="cyan")
        table.add_column("Language", style="green")
        table.add_column("Lines", justify="right", style="blue")

        for result in results[:20]:  # Limit to 20 results
            table.add_row(result["relative_path"], result["language"], str(result["lines_of_code"]))

        console.print()
        console.print(table)

        if len(results) > 20:
            console.print(f"\n[dim]Showing 20 of {len(results)} results[/dim]")

    except Exception as e:
        console.print(f"[bold red]Error:[/bold red] {e}")
        sys.exit(1)


@main.command()
@click.option("--path", type=click.Path(exists=True), help="Project path")
def stats(path: Optional[str]):
    """Show project and usage statistics"""
    project_path = Path(path) if path else Path.cwd()

    try:
        agent = GroknrollAgent(project_path)
        stats = agent.get_stats()

        # Project stats
        project = stats["project"]
        console.print()
        console.print(
            Panel.fit(
                f"[bold cyan]Project:[/bold cyan] {project['name']}\n"
                f"[cyan]Files:[/cyan] {project['files']}\n"
                f"[cyan]Lines of Code:[/cyan] {project['lines']:,}",
                title="[bold]Project Statistics[/bold]",
                border_style="cyan",
            )
        )

        # Language breakdown
        if project["languages"]:
            console.print()
            lang_table = Table(title="Languages", show_header=True)
            lang_table.add_column("Language", style="cyan")
            lang_table.add_column("Files", justify="right", style="green")
            lang_table.add_column("Lines", justify="right", style="blue")

            for lang, lang_stats in sorted(
                project["languages"].items(), key=lambda x: x[1]["lines"], reverse=True
            ):
                lang_table.add_row(lang, str(lang_stats["files"]), f"{lang_stats['lines']:,}")

            console.print(lang_table)

        # Execution stats
        exec_stats = stats["executions"]
        if exec_stats["total_executions"] > 0:
            console.print()
            console.print(
                Panel.fit(
                    f"[bold cyan]Total Executions:[/bold cyan] {exec_stats['total_executions']}\n"
                    f"[cyan]Successful:[/cyan] {exec_stats['successful']}\n"
                    f"[cyan]Failed:[/cyan] {exec_stats['failed']}\n"
                    f"[cyan]Total Cost:[/cyan] ${exec_stats['total_cost']:.4f}\n"
                    f"[cyan]Total Time:[/cyan] {exec_stats['total_time']:.1f}s\n"
                    f"[cyan]Avg Cost:[/cyan] ${exec_stats['avg_cost']:.4f}\n"
                    f"[cyan]Avg Time:[/cyan] {exec_stats['avg_time']:.1f}s",
                    title="[bold]RLM Usage Statistics[/bold]",
                    border_style="green",
                )
            )

    except Exception as e:
        console.print(f"[bold red]Error:[/bold red] {e}")
        sys.exit(1)


@main.command()
@click.option("--path", type=click.Path(exists=True), help="Project path")
@click.option("--limit", default=10, help="Number of recent items")
def history(path: Optional[str], limit: int):
    """Show recent execution history"""
    project_path = Path(path) if path else Path.cwd()

    try:
        agent = GroknrollAgent(project_path)
        history_items = agent.get_history(limit=limit)

        if not history_items:
            console.print("[yellow]No execution history yet[/yellow]")
            return

        # Display history in table
        table = Table(title="Recent Executions", show_header=True)
        table.add_column("Time", style="dim")
        table.add_column("Task", style="cyan")
        table.add_column("Status", style="green")
        table.add_column("Cost", justify="right", style="blue")
        table.add_column("Time", justify="right", style="magenta")

        for item in history_items:
            status_color = "green" if item["status"] == "success" else "red"
            table.add_row(
                item["timestamp"].strftime("%Y-%m-%d %H:%M"),
                item["task"],
                f"[{status_color}]{item['status']}[/{status_color}]",
                f"${item['cost']:.4f}" if item["cost"] else "N/A",
                f"{item['time']:.1f}s" if item["time"] else "N/A",
            )

        console.print()
        console.print(table)

    except Exception as e:
        console.print(f"[bold red]Error:[/bold red] {e}")
        sys.exit(1)


@main.command()
@click.option("--path", type=click.Path(exists=True), help="Project path")
def info(path: Optional[str]):
    """Show project information"""
    project_path = Path(path) if path else Path.cwd()

    try:
        agent = GroknrollAgent(project_path)
        info = agent.get_project_info()

        console.print()
        console.print(
            Panel.fit(
                f"[bold cyan]Name:[/bold cyan] {info['name']}\n"
                f"[cyan]Path:[/cyan] {info['path']}\n"
                f"[cyan]Files:[/cyan] {info['total_files']}\n"
                f"[cyan]Lines:[/cyan] {info['total_lines']:,}\n"
                f"[cyan]Last Indexed:[/cyan] {info['last_indexed']}",
                title="[bold]Project Information[/bold]",
                border_style="cyan",
            )
        )

    except Exception as e:
        console.print(f"[bold red]Error:[/bold red] {e}")
        sys.exit(1)


@main.command()
@click.option("--check", is_flag=True, help="Check for updates without installing")
@click.option("--pre", is_flag=True, help="Include pre-release versions")
def update(check: bool, pre: bool):
    """Update groknroll to the latest version"""
    import subprocess
    import json
    from packaging import version

    try:
        # Get current version
        current_version = __version__

        # Check PyPI for latest version
        console.print("[bold cyan]Checking for updates...[/bold cyan]")

        try:
            import requests
            response = requests.get("https://pypi.org/pypi/groknroll/json", timeout=5)
            response.raise_for_status()
            pypi_data = response.json()

            if pre:
                # Include all versions
                latest_version = pypi_data["info"]["version"]
            else:
                # Only stable versions
                releases = [v for v in pypi_data["releases"].keys()
                           if not any(x in v for x in ['a', 'b', 'rc', 'dev'])]
                latest_version = max(releases, key=lambda v: version.parse(v))

        except Exception as e:
            console.print(f"[bold red]Error checking PyPI:[/bold red] {e}")
            console.print("[yellow]Tip:[/yellow] Check your internet connection")
            sys.exit(1)

        console.print(f"\n[cyan]Current version:[/cyan] {current_version}")
        console.print(f"[cyan]Latest version:[/cyan] {latest_version}")

        # Compare versions
        if version.parse(current_version) >= version.parse(latest_version):
            console.print("\n[bold green]✓ You're already on the latest version![/bold green]")
            return

        console.print(f"\n[bold yellow]⚠ Update available:[/bold yellow] {current_version} → {latest_version}")

        # If just checking, stop here
        if check:
            console.print("\n[dim]Run 'groknroll update' to install the update[/dim]")
            return

        # Confirm update
        console.print("\n[bold]Update groknroll?[/bold]")
        response = input("Continue? [y/N]: ").strip().lower()

        if response not in ['y', 'yes']:
            console.print("[yellow]Update cancelled[/yellow]")
            return

        # Perform update
        console.print("\n[bold cyan]Updating groknroll...[/bold cyan]")

        # Detect package manager
        try:
            subprocess.run(["uv", "--version"], capture_output=True, check=True)
            package_manager = "uv"
            update_cmd = ["uv", "pip", "install", "--upgrade", "groknroll"]
        except (subprocess.CalledProcessError, FileNotFoundError):
            package_manager = "pip"
            update_cmd = [sys.executable, "-m", "pip", "install", "--upgrade", "groknroll"]

        console.print(f"[dim]Using {package_manager} to update...[/dim]")

        # Run update
        result = subprocess.run(
            update_cmd,
            capture_output=True,
            text=True
        )

        if result.returncode == 0:
            console.print(f"\n[bold green]✓ Successfully updated to version {latest_version}![/bold green]")
            console.print("\n[dim]Changes will take effect immediately[/dim]")

            # Show what's new (if available)
            try:
                release_notes_url = f"https://github.com/tekcin/groknroll/releases/tag/v{latest_version}"
                console.print(f"\n[cyan]Release notes:[/cyan] {release_notes_url}")
            except:
                pass

        else:
            console.print(f"\n[bold red]✗ Update failed[/bold red]")
            console.print(f"\n[yellow]Error:[/yellow]\n{result.stderr}")
            console.print("\n[dim]Try updating manually:[/dim]")
            console.print(f"  {' '.join(update_cmd)}")
            sys.exit(1)

    except KeyboardInterrupt:
        console.print("\n[yellow]Update cancelled[/yellow]")
        sys.exit(0)
    except Exception as e:
        console.print(f"[bold red]Error:[/bold red] {e}")
        import traceback
        console.print(f"[dim]{traceback.format_exc()}[/dim]")
        sys.exit(1)


# Add command groups
main.add_command(agent)
main.add_command(madace)
main.add_command(rlm)
main.add_command(oracle)


if __name__ == "__main__":
    main()
