"""
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 dotenv import load_dotenv

# Load .env file from current directory
load_dotenv()
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.cli.agent_commands import agent
from groknroll.cli.madace_commands import madace
from groknroll.cli.mcp_commands import mcp
from groknroll.cli.mode2600_commands import mode2600
from groknroll.cli.oracle_commands import oracle
from groknroll.cli.osint_commands import osint
from groknroll.cli.rlm_commands import rlm
from groknroll.cli.web_commands import serve, web
from groknroll.core.agent import GroknrollAgent

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(fsd_mode: bool = False):
    """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",
            fsd_mode=fsd_mode,
        )

        # Show warning if FSD mode is enabled
        if fsd_mode:
            console.print(
                "[bold yellow]⚠️  FSD MODE ENABLED[/bold yellow] - "
                "[yellow]All permission checks are DISABLED. Use with caution![/yellow]"
            )

        # 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.option(
    "--fsd",
    is_flag=True,
    help="FSD Mode: Skip ALL permission checks (dangerous!)",
)
@click.pass_context
def main(ctx, version, fsd):
    """
    🎸 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.

    \b
    FSD Mode (--fsd):
    Enables "Full Send Dangerous" mode which skips ALL permission
    checks including file access, bash commands, and sensitive file
    protection. Equivalent to --dangerously-skip-permissions.
    """
    # Store FSD mode in context for subcommands
    ctx.ensure_object(dict)
    ctx.obj["fsd_mode"] = fsd

    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(fsd_mode=fsd)


@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,
)
@click.pass_context
def chat(ctx, 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)
    fsd_mode = ctx.obj.get("fsd_mode", False) if ctx.obj else False

    try:
        if fsd_mode:
            console.print(
                "[bold yellow]⚠️  FSD MODE[/bold yellow] - "
                "[yellow]Permission checks disabled[/yellow]"
            )

        with console.status(f"[bold cyan]Thinking ({agent} agent)...") as status:
            groknroll_agent = GroknrollAgent(project_path, fsd_mode=fsd_mode)
            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

    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("\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)
main.add_command(mcp)
main.add_command(osint)
main.add_command(mode2600)
main.add_command(serve)
main.add_command(web)


if __name__ == "__main__":
    main()
