"""
Interactive CLI for Web Research Agent.
Provides a beautiful terminal interface with real-time ReAct step streaming,
multi-turn session memory, and query history navigation.
"""

import json
import logging
import os
import sys
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional

from rich.console import Console
from rich.live import Live
from rich.panel import Panel
from rich.prompt import Confirm, Prompt
from rich.table import Table
from rich.text import Text

try:
    import questionary
    _HAS_QUESTIONARY = True
except ImportError:
    _HAS_QUESTIONARY = False

console = Console()

ASCII_ART = r"""
██╗    ██╗███████╗██████╗     ██████╗ ███████╗███████╗███████╗ █████╗ ██████╗  ██████╗██╗  ██╗
██║    ██║██╔════╝██╔══██╗    ██╔══██╗██╔════╝██╔════╝██╔════╝██╔══██╗██╔══██╗██╔════╝██║  ██║
██║ █╗ ██║█████╗  ██████╔╝    ██████╔╝█████╗  ███████╗█████╗  ███████║██████╔╝██║     ███████║
██║███╗██║██╔══╝  ██╔══██╗    ██╔══██╗██╔══╝  ╚════██║██╔══╝  ██╔══██║██╔══██╗██║     ██╔══██║
╚███╔███╔╝███████╗██████╔╝    ██║  ██║███████╗███████║███████╗██║  ██║██║  ██║╚██████╗██║  ██║
 ╚══╝╚══╝ ╚══════╝╚═════╝     ╚═╝  ╚═╝╚══════╝╚══════╝╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝ ╚═════╝╚═╝  ╚═╝
"""

from webresearch import __version__ as VERSION
TAGLINE = "lock in, anon"

logging.getLogger().setLevel(logging.WARNING)

# ─── Session memory (persists for the lifetime of this CLI process) ───────────
from webresearch.memory import ConversationMemory
_session = ConversationMemory(max_pairs=5)


# ─── Banner ──────────────────────────────────────────────────────────────────

def print_banner():
    lines = ASCII_ART.strip().split("\n")
    colors = ["bright_blue", "blue", "dodger_blue2", "deep_sky_blue1", "blue", "bright_blue"]
    console.print()
    for i, line in enumerate(lines):
        console.print(line, style=f"bold {colors[i % len(colors)]}")
    console.print(Text(f"v{VERSION}", style="bold yellow"), justify="center")
    console.print(Text(TAGLINE, style="italic cyan"), justify="center")
    console.print("═" * 100, style="bright_blue")
    console.print()


# ─── Config ──────────────────────────────────────────────────────────────────

def get_config_path() -> Path:
    config_dir = Path.home() / ".webresearch"
    config_dir.mkdir(exist_ok=True)
    return config_dir / "config.env"


def load_config() -> dict:
    config_path = get_config_path()
    config = {}
    if config_path.exists():
        with open(config_path, "r") as f:
            for line in f:
                line = line.strip()
                if line and not line.startswith("#") and "=" in line:
                    key, value = line.split("=", 1)
                    config[key.strip()] = value.strip()
    return config


def save_config(config: dict):
    config_path = get_config_path()
    with open(config_path, "w") as f:
        f.write("# Web Research Agent Configuration\n")
        f.write("# This file is automatically generated\n\n")
        for key, value in config.items():
            f.write(f"{key}={value}\n")
    console.print(f"✓ Configuration saved to {config_path}", style="bold green")


def setup_api_keys() -> dict:
    console.print(
        Panel.fit(
            "🔧 [bold cyan]First-time Setup[/bold cyan]\nLet's configure your API keys.",
            border_style="cyan",
        )
    )
    console.print()
    config = {}

    console.print("[bold yellow]1. Gemini API Key[/bold yellow]")
    console.print("   Get yours at: https://makersuite.google.com/app/apikey")
    gemini_key = Prompt.ask("   [green]Enter Gemini API key[/green]").strip()
    if not gemini_key:
        console.print("[bold red]✗ Gemini API key is required![/bold red]")
        sys.exit(1)
    config["GEMINI_API_KEY"] = gemini_key

    console.print("\n[bold yellow]2. Serper API Key[/bold yellow]")
    console.print("   Get yours at: https://serper.dev")
    console.print("   [dim](Free tier: 2,500 searches/month)[/dim]")
    serper_key = Prompt.ask("   [green]Enter Serper API key[/green]").strip()
    if not serper_key:
        console.print("[bold red]✗ Serper API key is required![/bold red]")
        sys.exit(1)
    config["SERPER_API_KEY"] = serper_key

    console.print()
    save_config(config)
    console.print()
    return config


def check_config() -> dict:
    if os.path.exists(".env"):
        from dotenv import load_dotenv
        load_dotenv()
        config = {
            "GEMINI_API_KEY": os.getenv("GEMINI_API_KEY", ""),
            "SERPER_API_KEY": os.getenv("SERPER_API_KEY", ""),
            "MAX_ITERATIONS": os.getenv("MAX_ITERATIONS", "15"),
            "TEMPERATURE": os.getenv("TEMPERATURE", "0.1"),
            "MAX_TOOL_OUTPUT_LENGTH": os.getenv("MAX_TOOL_OUTPUT_LENGTH", "5000"),
            "MODEL_NAME": os.getenv("MODEL_NAME", "gemini-2.5-flash"),
            "WEB_REQUEST_TIMEOUT": os.getenv("WEB_REQUEST_TIMEOUT", "30"),
            "CODE_EXECUTION_TIMEOUT": os.getenv("CODE_EXECUTION_TIMEOUT", "60"),
        }
        if config["GEMINI_API_KEY"] and config["SERPER_API_KEY"]:
            console.print("✓ Using configuration from .env file", style="bold green")
            return config

    stored = load_config()
    if "GEMINI_API_KEY" not in stored or "SERPER_API_KEY" not in stored:
        console.print("⚠ Configuration not found or incomplete.\n", style="bold yellow")
        stored = setup_api_keys()
    # Only expose API keys from the persisted file — all other settings
    # come from package defaults in webresearch/config.py so they stay
    # up-to-date across upgrades without requiring a re-setup.
    return {
        "GEMINI_API_KEY": stored["GEMINI_API_KEY"],
        "SERPER_API_KEY": stored["SERPER_API_KEY"],
    }


def apply_config_to_env(config: dict):
    for key, value in config.items():
        os.environ[key] = value


# ─── History ─────────────────────────────────────────────────────────────────

def get_history_path() -> Path:
    history_dir = Path.home() / ".webresearch"
    history_dir.mkdir(exist_ok=True)
    return history_dir / "history.json"


def load_history() -> List[Dict]:
    path = get_history_path()
    if not path.exists():
        return []
    try:
        with open(path, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception:
        return []


def save_to_history(query: str, answer: str, steps: int, duration: float):
    history = load_history()
    history.insert(0, {
        "timestamp": datetime.now().isoformat(),
        "query": query,
        "answer_preview": answer[:200],
        "steps": steps,
        "duration": round(duration, 2),
    })
    path = get_history_path()
    with open(path, "w", encoding="utf-8") as f:
        json.dump(history[:50], f, indent=2)


def view_history():
    history = load_history()
    if not history:
        console.print("No query history yet.", style="bold yellow")
        return

    console.print(Panel.fit("📚 [bold cyan]Query History[/bold cyan]", border_style="cyan"))
    console.print()

    shown = history[:15]

    if _HAS_QUESTIONARY:
        # Arrow-key navigation
        choices = []
        for i, entry in enumerate(shown):
            ts = entry.get("timestamp", "")[:16].replace("T", " ")
            q = entry["query"]
            label = f"[{i+1:2d}] {q[:55]:<55}  {entry.get('steps','?'):>2}st  {entry.get('duration',0):>5.1f}s  {ts}"
            choices.append(questionary.Choice(title=label, value=i))
        choices.append(questionary.Choice(title="← Back", value=None))

        idx = questionary.select(
            "Select a query to re-run (↑↓ to navigate, Enter to select):",
            choices=choices,
        ).ask()

        if idx is not None:
            _run_query(shown[idx]["query"])
    else:
        # Fallback: numbered table
        table = Table(show_header=True, border_style="dim")
        table.add_column("#", style="cyan", width=4)
        table.add_column("Query", style="white", ratio=3)
        table.add_column("Steps", style="yellow", width=7, justify="right")
        table.add_column("Duration", style="dim", width=10, justify="right")
        table.add_column("Date", style="dim", width=19)

        for i, entry in enumerate(shown, 1):
            ts = entry.get("timestamp", "")[:16].replace("T", " ")
            q = entry["query"]
            table.add_row(
                str(i),
                q[:60] + ("…" if len(q) > 60 else ""),
                str(entry.get("steps", "?")),
                f"{entry.get('duration', 0):.1f}s",
                ts,
            )

        console.print(table)
        console.print()

        choice = Prompt.ask(
            "[green]Enter number to re-run[/green] (or press Enter to go back)", default=""
        )
        if choice.isdigit() and 1 <= int(choice) <= len(shown):
            _run_query(shown[int(choice) - 1]["query"])


# ─── Rate-limit display ───────────────────────────────────────────────────────

def _print_usage_banner():
    """Print Serper API monthly usage after a query completes."""
    try:
        from webresearch.tools.search import get_monthly_usage, _MONTHLY_LIMIT
        count = get_monthly_usage()
        pct = count / _MONTHLY_LIMIT * 100
        if pct < 70:
            style, icon = "dim green", "●"
        elif pct < 90:
            style, icon = "bold yellow", "⚠"
        else:
            style, icon = "bold red", "⛔"
        console.print(
            f"[{style}]{icon} Serper API: {count}/{_MONTHLY_LIMIT} searches this month "
            f"({pct:.0f}%)[/{style}]"
        )
    except Exception:
        pass


# ─── Agent initialization ────────────────────────────────────────────────────

def _build_tool_manager(cfg) -> "ToolManager":
    """Build a ToolManager with all available tools."""
    from webresearch.tools import (
        ToolManager, SearchTool, ScrapeTool, BrowserScrapeTool,
        CodeExecutorTool, FileOpsTool, playwright_available,
    )
    tool_manager = ToolManager()
    tool_manager.register_tool(SearchTool(cfg.serper_api_key))
    tool_manager.register_tool(ScrapeTool())
    if playwright_available():
        tool_manager.register_tool(BrowserScrapeTool())
    tool_manager.register_tool(CodeExecutorTool())
    tool_manager.register_tool(FileOpsTool())
    return tool_manager


def _build_llm_chain(cfg) -> "ModelFallbackChain":
    """
    Build a ModelFallbackChain from the available provider keys in cfg.

    Chain order:
      1. Gemini 2.5 Flash  (primary — always present)
      2. Groq / llama-3.3-70b-versatile  (if GROQ_API_KEY set)
      3. OpenRouter / llama-3.3-70b-instruct:free  (if OPENROUTER_API_KEY set)
      4. Ollama local  (if OLLAMA_BASE_URL set)
    """
    from webresearch.llm import LLMInterface
    from webresearch.llm_compat import OpenAICompatibleLLMInterface, openai_available, PROVIDERS
    from webresearch.llm_chain import ModelFallbackChain

    interfaces = []

    # Primary: Gemini
    gemini = LLMInterface(
        api_key=cfg.gemini_api_key,
        model_name=cfg.model_name,
        temperature=cfg.temperature,
    )
    gemini.provider_name = f"Gemini ({cfg.model_name})"
    interfaces.append(gemini)

    if openai_available():
        # Groq fallback
        if cfg.groq_api_key:
            base_url, display, model = PROVIDERS["groq"]
            interfaces.append(OpenAICompatibleLLMInterface(
                api_key=cfg.groq_api_key,
                model_name=model,
                base_url=base_url,
                provider_name=f"Groq ({model})",
                temperature=cfg.temperature,
            ))

        # OpenRouter fallback
        if cfg.openrouter_api_key:
            base_url, display, model = PROVIDERS["openrouter"]
            interfaces.append(OpenAICompatibleLLMInterface(
                api_key=cfg.openrouter_api_key,
                model_name=model,
                base_url=base_url,
                provider_name=f"OpenRouter ({model})",
                temperature=cfg.temperature,
            ))

        # Ollama fallback
        if cfg.ollama_base_url:
            _, _, model = PROVIDERS["ollama"]
            interfaces.append(OpenAICompatibleLLMInterface(
                api_key="ollama",
                model_name=model,
                base_url=cfg.ollama_base_url,
                provider_name=f"Ollama ({model})",
                temperature=cfg.temperature,
            ))

    def _on_switch(from_name: str, to_name: str):
        console.print(
            f"\n[bold yellow]Rate limit reached on {from_name}. "
            f"Switching to {to_name}...[/bold yellow]\n"
        )

    chain = ModelFallbackChain(interfaces=interfaces, switch_callback=_on_switch)

    if len(interfaces) > 1:
        names = " -> ".join(
            getattr(i, "provider_name", getattr(i, "model_name", "?"))
            for i in interfaces
        )
        console.print(f"[dim]Model chain: {names}[/dim]")

    return chain


def initialize_agent():
    """Initialize the sequential ReAct agent with a model fallback chain."""
    from webresearch.config import Config
    from webresearch.agent import ReActAgent

    cfg = Config()
    cfg.validate()
    return ReActAgent(
        llm=_build_llm_chain(cfg),
        tool_manager=_build_tool_manager(cfg),
        max_iterations=cfg.max_iterations,
    )


def initialize_parallel_agent():
    """Initialize the parallel fan-out research agent with a model fallback chain."""
    from webresearch.config import Config
    from webresearch.parallel import ParallelResearchAgent

    cfg = Config()
    cfg.validate()
    return ParallelResearchAgent(
        llm=_build_llm_chain(cfg),
        tool_manager=_build_tool_manager(cfg),
    )


# ─── Core query runner ────────────────────────────────────────────────────────

def _run_query(query: str):
    """Execute a research query with live step-by-step output and session memory."""
    try:
        agent = initialize_agent()
    except Exception as e:
        console.print(f"✗ Error initializing agent: {str(e)}", style="bold red")
        console.print("Tip: Reconfigure API keys with option 5.", style="yellow")
        return

    # Inject previous session context into the task
    task = _session.build_task_with_memory(query)
    if len(_session) > 0:
        console.print(
            f"[dim]↑ Using {len(_session)} previous Q&A pair(s) as context[/dim]\n"
        )

    start_time = datetime.now()
    step_rows: List[Dict] = []

    def make_step_table(rows: List[Dict], status: str = "") -> Table:
        title = "[bold cyan]ReAct Loop[/bold cyan]"
        if status:
            title += f" [dim]{status}[/dim]"
        t = Table(title=title, border_style="cyan", expand=True, show_lines=False)
        t.add_column("Step", style="cyan", width=5, justify="center")
        t.add_column("Thought", style="white", ratio=3)
        t.add_column("Action", style="yellow", width=22)
        t.add_column("Obs.", style="dim", width=10, justify="right")
        for r in rows:
            t.add_row(
                str(r["n"]),
                r["thought"],
                r["action"],
                f"{r['obs_len']} ch" if r["obs_len"] else "—",
            )
        return t

    answer: Optional[str] = None

    with Live(make_step_table([], "thinking…"), console=console, refresh_per_second=4) as live:
        def step_callback(iteration: int, step: Any):
            thought = step.thought
            if len(thought) > 90:
                thought = thought[:87] + "…"
            step_rows.append({
                "n": iteration,
                "thought": thought,
                "action": step.action or "—",
                "obs_len": len(step.observation or ""),
            })
            live.update(make_step_table(step_rows, f"step {iteration}"))

        answer = agent.run(task, step_callback=step_callback)
        live.update(make_step_table(step_rows, "complete ✓"))

    duration = (datetime.now() - start_time).total_seconds()

    console.print()
    console.rule("[bold green]RESULT[/bold green]", style="green")
    console.print()

    border = "red" if answer.startswith("⚠ Error:") else ("yellow" if answer.startswith("⚠") else "green")
    console.print(Panel(answer, border_style=border, padding=(1, 2)))
    console.print()
    console.print(
        f"⏱  [yellow]{duration:.2f}s[/yellow]  [dim]│[/dim]  "
        f"[cyan]{len(step_rows)} steps[/cyan]"
    )
    _print_usage_banner()
    console.print()

    # Save to session memory and persistent history
    _session.add(query, answer)
    save_to_history(query, answer, len(step_rows), duration)

    if Confirm.ask("Save result to file?", default=False):
        filename = Prompt.ask("Filename", default="result.txt")
        with open(filename, "w", encoding="utf-8") as f:
            f.write(f"Query: {query}\n{'=' * 80}\n\n{answer}\n\n")
            f.write(f"{'─' * 80}\nExecution time: {duration:.2f}s | Steps: {len(step_rows)}\n")
        console.print(f"✓ Saved to [cyan]{filename}[/cyan]", style="bold green")


# ─── Deep research (parallel fan-out) ────────────────────────────────────────

def _run_deep_research(query: str):
    """Execute a query via the parallel fan-out agent with a live status board."""
    try:
        agent = initialize_parallel_agent()
    except Exception as e:
        console.print(f"✗ Error initializing agent: {str(e)}", style="bold red")
        console.print("Tip: Reconfigure API keys with option 5.", style="yellow")
        return

    if len(_session) > 0:
        query = _session.build_task_with_memory(query)
        console.print(f"[dim]↑ Using {len(_session)} previous Q&A pair(s) as context[/dim]\n")

    start_time = datetime.now()
    sub_status: Dict[int, Dict] = {}

    def make_status_board() -> Table:
        t = Table(
            title="[bold cyan]Deep Research — Parallel Fan-out[/bold cyan]",
            border_style="cyan",
            expand=True,
        )
        t.add_column("#", style="cyan", width=4, justify="center")
        t.add_column("Sub-query", style="white", ratio=4)
        t.add_column("Status", width=14)
        for idx in sorted(sub_status):
            s = sub_status[idx]
            state = s["state"]
            icons = {"pending": "○ pending", "running": "⟳ running", "done": "✓ done", "error": "✗ error"}
            styles = {"pending": "dim", "running": "bold cyan", "done": "bold green", "error": "bold red"}
            t.add_row(
                str(idx + 1),
                s.get("question", "…")[:70],
                f"[{styles[state]}]{icons[state]}[/{styles[state]}]",
            )
        return t

    answer: Optional[str] = None

    with Live(make_status_board(), console=console, refresh_per_second=4) as live:
        def cb(idx: int, state: str, question: Optional[str] = None):
            if idx not in sub_status:
                sub_status[idx] = {"question": question or "…", "state": state}
            else:
                sub_status[idx]["state"] = state
                if question:
                    sub_status[idx]["question"] = question
            live.update(make_status_board())

        answer = agent.run(query, sub_status_callback=cb)

    duration = (datetime.now() - start_time).total_seconds()
    n_sub = len(sub_status)

    console.print()
    console.rule("[bold green]RESULT[/bold green]", style="green")
    console.print()
    border = "red" if answer.startswith("⚠ Error:") else ("yellow" if answer.startswith("⚠") else "green")
    console.print(Panel(answer, border_style=border, padding=(1, 2)))
    console.print()
    console.print(
        f"⏱  [yellow]{duration:.2f}s[/yellow]  [dim]│[/dim]  "
        f"[cyan]{n_sub} parallel sub-queries[/cyan]"
    )
    _print_usage_banner()
    console.print()

    _session.add(query, answer)
    save_to_history(query, answer, n_sub, duration)

    if Confirm.ask("Save result to file?", default=False):
        filename = Prompt.ask("Filename", default="result.txt")
        with open(filename, "w", encoding="utf-8") as f:
            f.write(f"Query: {query}\n{'=' * 80}\n\n{answer}\n\n")
            f.write(f"{'─' * 80}\nExecution time: {duration:.2f}s | Sub-queries: {n_sub}\n")
        console.print(f"✓ Saved to [cyan]{filename}[/cyan]", style="bold green")


# ─── Menu actions ─────────────────────────────────────────────────────────────

def show_menu():
    table = Table(show_header=False, box=None, padding=(0, 2))
    table.add_column(style="cyan bold")
    table.add_column(style="white")
    table.add_row("1.", "[green]🔍 Run a research query[/green]")
    table.add_row("2.", "[yellow]📁 Process tasks from file[/yellow]")
    table.add_row("3.", "[cyan]📚 View query history[/cyan]")
    table.add_row("4.", "[blue]📋 View recent logs[/blue]")
    table.add_row("5.", "[magenta]🔧 Reconfigure API keys[/magenta]")
    table.add_row("6.", "[dim]🧹 Clear session memory[/dim]")
    table.add_row("7.", "[red]👋 Exit[/red]")

    session_note = ""
    if len(_session) > 0:
        session_note = f"\n[dim]Session: {len(_session)} Q&A pair(s) in context[/dim]"

    console.print(
        Panel(
            table,
            title="[bold cyan]What would you like to do?[/bold cyan]",
            subtitle=session_note,
            border_style="cyan",
        )
    )
    console.print()


def run_interactive_query():
    console.print(
        Panel.fit("🔍 [bold cyan]Research Query Mode[/bold cyan]", border_style="cyan")
    )
    console.print()
    query = Prompt.ask(
        "[green]❯[/green] Enter your research question (or type 'back' to return)"
    )
    if not query or query.lower() == "back":
        return

    if _HAS_QUESTIONARY:
        mode = questionary.select(
            "Research mode:",
            choices=[
                questionary.Choice("Standard  — sequential ReAct loop (fast, ~1 min)", value="standard"),
                questionary.Choice("Deep      — parallel fan-out: 4 sub-queries × 5 steps (thorough, ~3 min)", value="deep"),
            ],
        ).ask()
        if mode is None:
            return
    else:
        console.print("\n[cyan]Mode:[/cyan] 1=Standard  2=Deep Research")
        raw = Prompt.ask("[green]❯[/green] Choose mode", choices=["1", "2"], default="1")
        mode = "standard" if raw == "1" else "deep"

    console.print()
    if mode == "deep":
        _run_deep_research(query)
    else:
        _run_query(query)


def run_tasks_from_file():
    console.print(
        Panel.fit("📁 [bold cyan]Process Tasks from File[/bold cyan]", border_style="cyan")
    )
    console.print()

    filepath = Prompt.ask("[green]❯[/green] Path to tasks file (or 'back' to return)")
    if not filepath or filepath.lower() == "back":
        return

    if not os.path.exists(filepath):
        console.print(f"✗ File not found: {filepath}", style="bold red")
        return

    if not os.path.isfile(filepath):
        console.print(f"✗ That path is a directory, not a file: {filepath}", style="bold red")
        return

    output_file = Prompt.ask("Output file", default="results.txt")
    console.print(f"\n[yellow]Processing tasks from:[/yellow] {filepath}")
    console.print(f"[yellow]Results will be saved to:[/yellow] {output_file}\n")

    def read_tasks(task_file: str) -> List[str]:
        with open(task_file, "r", encoding="utf-8") as f:
            tasks, current = [], []
            for line in f:
                line = line.rstrip()
                if not line:
                    if current:
                        tasks.append("\n".join(current))
                        current = []
                else:
                    current.append(line)
            if current:
                tasks.append("\n".join(current))
        return tasks

    try:
        tasks = read_tasks(filepath)
        agent = initialize_agent()
        results = []

        for i, task in enumerate(tasks, 1):
            console.print(f"[cyan][Task {i}/{len(tasks)}][/cyan] {task[:60]}…")
            start_time = datetime.now()
            try:
                answer = agent.run(task)
                duration = (datetime.now() - start_time).total_seconds()
                results.append({
                    "task": task,
                    "answer": answer,
                    "execution_time": round(duration, 2),
                    "num_steps": len(agent.get_execution_trace()),
                })
                console.print(f"[green]✓ Completed in {duration:.2f}s[/green]\n")
            except Exception as e:
                console.print(f"[red]✗ Error: {str(e)}[/red]\n")
                results.append({"task": task, "answer": "Error during processing", "error": str(e)})

        with open(output_file, "w", encoding="utf-8") as f:
            f.write("=" * 100 + "\nWEB RESEARCH AGENT RESULTS\n")
            f.write(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
            f.write("=" * 100 + "\n\n")
            for i, result in enumerate(results, 1):
                f.write(f"\n{'=' * 100}\nTASK {i}\n{'=' * 100}\n\n")
                f.write(f"TASK DESCRIPTION:\n{result['task']}\n\n{'-' * 100}\n\n")
                f.write(f"ANSWER:\n{result['answer']}\n\n")
                if result.get("error"):
                    f.write(f"ERROR: {result['error']}\n\n")
                f.write(f"Execution time: {result.get('execution_time', 'N/A')} seconds\n")
                f.write(f"Number of steps: {result.get('num_steps', 'N/A')}\n")

        console.print(f"[green]✓ All tasks completed! Results saved to {output_file}[/green]\n")
        _print_usage_banner()

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


def view_logs():
    logs_dir = Path("logs")
    if not logs_dir.exists() or not list(logs_dir.glob("*.log")):
        console.print("⚠ No log files found.", style="bold yellow")
        return

    log_files = sorted(logs_dir.glob("*.log"), key=lambda x: x.stat().st_mtime, reverse=True)

    console.print(Panel.fit("📋 [bold cyan]Recent Log Files[/bold cyan]", border_style="cyan"))
    console.print()

    table = Table(show_header=True, box=None)
    table.add_column("#", style="cyan", width=4)
    table.add_column("Filename", style="green")
    table.add_column("Size", style="yellow", justify="right")
    table.add_column("Modified", style="white")

    for i, log_file in enumerate(log_files[:5], 1):
        size = log_file.stat().st_size / 1024
        time_str = datetime.fromtimestamp(log_file.stat().st_mtime).strftime("%Y-%m-%d %H:%M:%S")
        table.add_row(str(i), log_file.name, f"{size:.1f} KB", time_str)

    console.print(table)
    console.print()

    choice = Prompt.ask("[green]Enter number to view[/green] (or press Enter to skip)", default="")

    if choice.isdigit() and 1 <= int(choice) <= len(log_files[:5]):
        log_file = log_files[int(choice) - 1]
        with open(log_file, "r", encoding="utf-8") as f:
            lines = f.read().split("\n")

        console.print()
        console.rule(f"[bold cyan]Log: {log_file.name}[/bold cyan]", style="cyan")
        console.print()

        if len(lines) > 100:
            console.print("[yellow][Showing last 100 lines...][/yellow]\n")
            lines = lines[-100:]

        for line in lines:
            if "ERROR" in line:
                console.print(line, style="bold red")
            elif "WARNING" in line:
                console.print(line, style="bold yellow")
            else:
                console.print(line)

        console.print()
        console.rule(style="cyan")
        console.print()


# ─── Main ────────────────────────────────────────────────────────────────────

def main():
    print_banner()

    config = check_config()
    apply_config_to_env(config)
    console.print("✓ Configuration loaded", style="bold green")
    console.print()

    while True:
        show_menu()
        choice = Prompt.ask(
            "[green]❯[/green] Choose an option", choices=["1", "2", "3", "4", "5", "6", "7"]
        )
        console.print()

        if choice == "1":
            run_interactive_query()
        elif choice == "2":
            run_tasks_from_file()
        elif choice == "3":
            view_history()
        elif choice == "4":
            view_logs()
        elif choice == "5":
            config = setup_api_keys()
            apply_config_to_env(config)
        elif choice == "6":
            _session.clear()
            console.print("✓ Session memory cleared.", style="bold green")
            console.print()
        elif choice == "7":
            console.print(
                Panel.fit(
                    "👋 [bold cyan]Thanks for using Web Research Agent![/bold cyan]\nStay curious, anon.",
                    border_style="cyan",
                )
            )
            sys.exit(0)


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        console.print("\n[bold cyan]Goodbye! 👋[/bold cyan]\n")
        sys.exit(0)
