"""Ralph Mode - Autonomous looping for IEUM.

Ralph is an autonomous looping pattern created by Geoff Huntley.
Each loop starts with fresh context. The filesystem and git serve as memory.

Usage via CLI:
    ieum ralph "Build a Python course. Use git."
    ieum ralph "Build a REST API" --iterations 5
"""

from __future__ import annotations

import argparse
import asyncio
import sys
from pathlib import Path
from typing import Any

from ieum.agent import create_cli_agent
from ieum.config import COLORS, SessionState, console, create_model, settings
from ieum.tools import fetch_url, http_request, python_repl, web_search


async def run_ralph_iteration(
    task: str,
    iteration: int,
    max_iterations: int,
    agent: Any,
    backend: Any,
    thread_id: str,
) -> None:
    """Run a single Ralph iteration.

    Args:
        task: The task to work on
        iteration: Current iteration number
        max_iterations: Maximum iterations (0 = unlimited)
        agent: The agent instance
        backend: The backend instance
        thread_id: Thread ID for this session
    """
    iter_display = f"{iteration}/{max_iterations}" if max_iterations > 0 else str(iteration)

    prompt = f"""## Ralph Mode - Iteration {iter_display}

Your previous work is in the filesystem. Check what exists and keep building.

**TASK:**
{task}

**Instructions:**
1. First, check the current state of files (use ls, read_file, glob)
2. Review any existing work from previous iterations
3. Make meaningful progress on the task
4. Use git to track your changes if appropriate
5. You'll be called again in the next iteration

Make progress. Focus on the task."""

    config = {"configurable": {"thread_id": thread_id}}

    # Stream the response
    console.print(f"\n[dim]Processing...[/dim]")

    try:
        result = agent.invoke(
            {"messages": [("user", prompt)]},
            config=config,
        )

        # Print the final assistant message
        for msg in result.get("messages", []):
            if hasattr(msg, "type") and msg.type == "ai" and msg.content:
                content = str(msg.content)
                if len(content) > 2000:
                    content = content[:2000] + "\n\n[... truncated ...]"
                console.print(f"\n[green]Agent:[/green] {content}")
                break

    except Exception as e:
        console.print(f"\n[red]Error in iteration {iteration}:[/red] {e}")
        raise


async def ralph_loop(
    task: str,
    max_iterations: int = 0,
    model_name: str | None = None,
    work_dir: Path | None = None,
) -> None:
    """Run agent in Ralph loop.

    Args:
        task: The task to work on (declarative, what you want)
        max_iterations: Maximum iterations (0 = unlimited, Ctrl+C to stop)
        model_name: Optional model name to use
        work_dir: Optional working directory (defaults to current directory)
    """
    from langgraph.checkpoint.memory import InMemorySaver

    # Use current directory or specified work_dir
    if work_dir is None:
        work_dir = Path.cwd()

    model = create_model(model_name)

    # Create tools
    tools = [http_request, fetch_url, python_repl]
    if settings.has_tavily:
        tools.append(web_search)

    # Create agent with auto-approve (Ralph mode is autonomous)
    agent, backend = create_cli_agent(
        model=model,
        assistant_id="ralph",
        tools=tools,
        auto_approve=True,
        enable_memory=True,
        enable_skills=True,
        enable_shell=True,
        checkpointer=InMemorySaver(),
    )

    # Display header
    console.print()
    console.print(f"[bold {COLORS['primary']}]╔══════════════════════════════════════════════════════════╗[/bold {COLORS['primary']}]")
    console.print(f"[bold {COLORS['primary']}]║                     RALPH MODE                           ║[/bold {COLORS['primary']}]")
    console.print(f"[bold {COLORS['primary']}]╚══════════════════════════════════════════════════════════╝[/bold {COLORS['primary']}]")
    console.print()
    console.print(f"[bold]Task:[/bold] {task}")
    console.print(f"[bold]Iterations:[/bold] {'unlimited (Ctrl+C to stop)' if max_iterations == 0 else max_iterations}")
    console.print(f"[bold]Working Directory:[/bold] {work_dir}")
    console.print()

    iteration = 1
    thread_id = f"ralph-{iteration}"

    try:
        while max_iterations == 0 or iteration <= max_iterations:
            console.print(f"\n[bold cyan]{'═' * 60}[/bold cyan]")
            console.print(f"[bold cyan]  RALPH ITERATION {iteration}[/bold cyan]")
            console.print(f"[bold cyan]{'═' * 60}[/bold cyan]")

            # Each iteration gets a fresh thread (fresh context)
            thread_id = f"ralph-{iteration}"

            await run_ralph_iteration(
                task=task,
                iteration=iteration,
                max_iterations=max_iterations,
                agent=agent,
                backend=backend,
                thread_id=thread_id,
            )

            iteration += 1

            if max_iterations == 0 or iteration <= max_iterations:
                console.print(f"\n[dim]...continuing to iteration {iteration}[/dim]")

    except KeyboardInterrupt:
        console.print(f"\n\n[bold yellow]Ralph stopped after {iteration - 1} iteration(s)[/bold yellow]")

    # Show summary
    console.print(f"\n[bold]{'═' * 60}[/bold]")
    console.print(f"[bold]Ralph Mode Complete[/bold]")
    console.print(f"[bold]{'═' * 60}[/bold]")
    console.print(f"\n[dim]Total iterations: {iteration - 1}[/dim]")
    console.print(f"[dim]Working directory: {work_dir}[/dim]")

    # List created/modified files
    console.print(f"\n[bold]Files in working directory:[/bold]")
    try:
        files = sorted(work_dir.rglob("*"))
        file_count = 0
        for f in files:
            if f.is_file() and ".git" not in str(f) and "__pycache__" not in str(f):
                rel_path = f.relative_to(work_dir)
                console.print(f"  {rel_path}", style="dim")
                file_count += 1
                if file_count >= 20:
                    remaining = len([x for x in files if x.is_file()]) - file_count
                    if remaining > 0:
                        console.print(f"  ... and {remaining} more files", style="dim")
                    break
    except Exception:
        pass


def setup_ralph_parser(subparsers: Any) -> argparse.ArgumentParser:
    """Setup the ralph subcommand parser.

    Args:
        subparsers: The subparsers object from argparse

    Returns:
        The ralph parser
    """
    ralph_parser = subparsers.add_parser(
        "ralph",
        help="Run Ralph Mode - autonomous looping agent",
        description="""Ralph Mode - Autonomous looping for IEUM.

Ralph is an autonomous looping pattern created by Geoff Huntley.
Each loop starts with fresh context. The filesystem and git serve as memory.

Examples:
  ieum ralph "Build a Python course. Use git."
  ieum ralph "Build a REST API" --iterations 5
  ieum ralph "Create a CLI tool" --model ollama/qwen3:4b
""",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    ralph_parser.add_argument(
        "task",
        help="Task to work on (declarative, what you want)",
    )

    ralph_parser.add_argument(
        "--iterations",
        "-i",
        type=int,
        default=0,
        help="Max iterations (0 = unlimited, default: unlimited). Use Ctrl+C to stop.",
    )

    ralph_parser.add_argument(
        "--model",
        help="Model to use (e.g., ollama/llama3, lmstudio/qwen2.5)",
    )

    ralph_parser.add_argument(
        "--dir",
        "-d",
        dest="work_dir",
        type=Path,
        default=None,
        help="Working directory (default: current directory)",
    )

    return ralph_parser


def execute_ralph_command(args: argparse.Namespace) -> None:
    """Execute the ralph command.

    Args:
        args: Parsed command line arguments
    """
    try:
        asyncio.run(
            ralph_loop(
                task=args.task,
                max_iterations=args.iterations,
                model_name=getattr(args, "model", None),
                work_dir=getattr(args, "work_dir", None),
            )
        )
    except KeyboardInterrupt:
        pass  # Clean exit on Ctrl+C


__all__ = [
    "ralph_loop",
    "setup_ralph_parser",
    "execute_ralph_command",
]
