"""CLI entry point for agentgog."""

import json
import sys
import tempfile
from pathlib import Path
from typing import Optional

import click
from rich.console import Console
from rich.table import Table
from importlib.metadata import version as get_package_version

from agentgog.zz_models import Result
from agentgog.zz_models_list import ModelEntry, parse_models_list
from agentgog.zz_output_formatter import (
    create_result,
    sanitize_filename,
    save_result,
)
from agentgog.zz_runner import read_file_content, run_agata_chat, run_agata_compare
from agentgog.zz_yaml_loader import TaskLoadError, load_task

console = Console()


def process_single_model(
    task_file: str,
    model_entry: ModelEntry,
    results_dir: str,
    temp_dir: str,
    mode: str = "chat",
    timeout: Optional[int] = None
) -> Result:
    """Process a single model against a task.
    
    Workflow:
    1. Run agata chat to get model output
    2. Run agata compare to validate output
    3. Create and return Result object
    
    Args:
        task_file: Path to YAML task file
        model_entry: ModelEntry with provider and model
        results_dir: Directory to save results
        temp_dir: Directory for temporary files
        mode: Mode of operation ('chat' or 'code')
        timeout: Timeout for chat command
        
    Returns:
        Result object
    """
    provider = model_entry.provider
    model = model_entry.model
    
    # Load task to get expected answer
    try:
        task = load_task(task_file)
    except TaskLoadError as e:
        console.print(f"[red]Error loading task:[/red] {e}")
        return Result(
            task_id="unknown",
            model=model,
            provider=provider,
            timestamp="",
            time_sec=0.0,
            success=False,
            error=str(e)
        )
    
    # Create temp files for outputs (include mode in filename)
    safe_model_name = sanitize_filename(model)
    model_output_file = Path(temp_dir) / f"{task.id}_{mode}_{safe_model_name}_output.txt"
    compare_output_file = Path(temp_dir) / f"{task.id}_{mode}_{safe_model_name}_compare.txt"
    
    console.print(f"\n[blue]Processing {provider}/{model}...[/blue]")
    
    # Check if output file already exists - skip if it does
    if model_output_file.exists():
        console.print(f"  [red]Output file already exists, skipping. Output: {model_output_file.name}[/red]")
        # Try to read existing files and create result
        model_output = read_file_content(str(model_output_file))
        compare_output = read_file_content(str(compare_output_file))
        
        if model_output is None:
            return create_result(
                task=task,
                model=model,
                provider=provider,
                success=False,
                execution_time=0.0,
                error="Cannot read existing output file"
            )
        
        is_correct = False
        verification_result = None
        if compare_output:
            verification_result = compare_output.strip().lower()
            is_correct = verification_result in ('same', 'similar', 'true', 'yes', '1', 'correct', 'match')
        
        return create_result(
            task=task,
            model=model,
            provider=provider,
            success=True,
            execution_time=0.0,
            output=model_output,
            correct=is_correct,
            verification_result=verification_result
        )
    
    # Step 1: Run agata chat
    console.print(f"  [dim]Running agata chat...[/dim]")
    chat_success, chat_error, chat_time = run_agata_chat(
        task_file=task_file,
        provider=provider,
        model=model,
        output_file=str(model_output_file),
        timeout=timeout
    )
    
    if not chat_success:
        console.print(f"  [red]Chat failed:[/red] {chat_error}")
        return create_result(
            task=task,
            model=model,
            provider=provider,
            success=False,
            execution_time=chat_time,
            error=chat_error
        )
    
    # Read model output
    model_output = read_file_content(str(model_output_file))
    if model_output is None:
        error_msg = "Model output file not found"
        console.print(f"  [red]{error_msg}[/red]")
        return create_result(
            task=task,
            model=model,
            provider=provider,
            success=False,
            execution_time=chat_time,
            error=error_msg
        )
    
    console.print(f"  [green]Chat completed in {chat_time:.2f}s[/green]")
    
    # Display model output (trimmed to 80 chars)
    if model_output:
        display_output = model_output.strip()
        if len(display_output) > 80:
            display_output = display_output[:77] + "..."
        console.print(f"  [dim]Output: '{display_output}'[/dim]")
    
    # Step 2: Run agata compare for validation
    console.print(f"  [dim]Running agata compare...[/dim]")
    compare_success, compare_error, compare_time = run_agata_compare(
        result_file=str(model_output_file),
        task_file=task_file,
        output_file=str(compare_output_file),
        timeout=60
    )
    
    total_time = chat_time + compare_time
    
    if not compare_success:
        console.print(f"  [yellow]Compare failed:[/yellow] {compare_error}")
        # Chat succeeded but compare failed - verification_result is None
        return create_result(
            task=task,
            model=model,
            provider=provider,
            success=True,  # Chat succeeded
            execution_time=total_time,
            output=model_output,
            correct=False,
            verification_result=None,
            error=f"Validation failed: {compare_error}"
        )
    
    # Read compare output to determine if correct
    compare_output = read_file_content(str(compare_output_file))
    is_correct = False
    verification_result = None
    
    if compare_output:
        # Parse comparison result - agata compare outputs various words for match
        verification_result = compare_output.strip().lower()
        # Validation passes for 'same', 'similar', 'true', 'yes', '1', 'correct', 'match'
        is_correct = verification_result in ('same', 'similar', 'true', 'yes', '1', 'correct', 'match')
    
    if is_correct:
        console.print(f"  [green]Validation passed ({verification_result})[/green]")
    else:
        console.print(f"  [yellow]Validation failed ({verification_result})[/yellow]")
    
    return create_result(
        task=task,
        model=model,
        provider=provider,
        success=True,
        execution_time=total_time,
        output=model_output,
        correct=is_correct,
        verification_result=verification_result
    )


def print_version(ctx, param, value):
    if not value or ctx.resilient_parsing:
        return
    click.echo(get_package_version("agentgog"))
    ctx.exit()


@click.group()
@click.option('--version', '-v', is_flag=True, callback=print_version, expose_value=False, is_eager=True, help='Show version and exit')
def main():
    """AgentGOG - Model testing and evaluation framework."""
    pass


@main.command()
@click.option('-f', '--file', 'task_file', required=True,
              help='Path to the YAML task file')
@click.option('-m', '--models', 'models_file', default='./models.list',
              help='Path to models.list file (default: ./models.list)')
@click.option('-b', '--banned', 'banned_file', default='./models_banned.list',
              help='Path to models_banned.list file (default: ./models_banned.list)')
@click.option('--results-dir', default='./results',
              help='Directory to save JSON results (default: ./results)')
@click.option('--temp-dir', default='./temp',
              help='Directory for temporary files (default: ./temp)')
@click.option('--timeout', type=int, default=300,
              help='Timeout in seconds for each model (default: 300)')
@click.option('--mode', type=click.Choice(['chat', 'code'], case_sensitive=False), 
              default='chat', help='Mode of operation: chat or code (default: chat)')
def run(task_file: str, models_file: str, banned_file: str, results_dir: str, temp_dir: str, timeout: int, mode: str):
    """Run task against all models in models.list."""
    
    # Parse models.list with banned list filtering
    try:
        models = parse_models_list(models_file, banned_file)
        console.print(f"[green]Loaded {len(models)} models from {models_file}[/green]")
        if Path(banned_file).exists():
            from agentgog.zz_models_list import parse_banned_models_list
            banned_models = parse_banned_models_list(banned_file)
            if banned_models:
                console.print(f"[yellow]Excluded {len(banned_models)} banned models from {banned_file}[/yellow]")
    except FileNotFoundError:
        console.print(f"[red]Models list file not found:[/red] {models_file}")
        sys.exit(1)
    except ValueError as e:
        console.print(f"[red]Error parsing models.list:[/red] {e}")
        sys.exit(1)
    
    if not models:
        console.print("[yellow]No models found in models.list[/yellow]")
        sys.exit(0)
    
    # Create directories
    Path(results_dir).mkdir(parents=True, exist_ok=True)
    Path(temp_dir).mkdir(parents=True, exist_ok=True)
    
    # Process each model
    results = []
    for model_entry in models:
        result = process_single_model(
            task_file=task_file,
            model_entry=model_entry,
            results_dir=results_dir,
            temp_dir=temp_dir,
            mode=mode,
            timeout=timeout
        )
        results.append(result)
        
        # Save result immediately with mode in filename (overwrite if exists)
        filename = f"{sanitize_filename(result.task_id)}_{mode}_{sanitize_filename(result.provider)}_{sanitize_filename(result.model)}.json"
        filepath = save_result(result, results_dir, filename)
        console.print(f"  [dim]Saved: {filepath}[/dim]")
    
    # Summary
    successful = sum(1 for r in results if r.success)
    correct = sum(1 for r in results if r.correct)
    
    console.print(f"\n[green]Completed:[/green] {successful}/{len(results)} successful, {correct}/{len(results)} correct")


@main.command()
@click.argument('results_dir', default='./results')
def summary(results_dir: str):
    """Display a summary of all results."""
    results_path = Path(results_dir)
    
    if not results_path.exists():
        console.print(f"[red]Results directory not found:[/red] {results_dir}")
        sys.exit(1)
    
    table = Table(title="Test Results Summary")
    table.add_column("Task ID", style="cyan")
    table.add_column("Model", style="magenta")
    table.add_column("Provider", style="green")
    table.add_column("Time (s)", justify="right")
    table.add_column("Success", justify="center")
    table.add_column("Correct", justify="center")
    
    result_files = list(results_path.glob('*.json'))
    
    if not result_files:
        console.print(f"[yellow]No result files found in {results_dir}[/yellow]")
        sys.exit(0)
    
    for result_file in sorted(result_files):
        with open(result_file) as f:
            data = json.load(f)
        
        success_str = "✓" if data.get('success') else "✗"
        success_style = "green" if data.get('success') else "red"
        
        correct = data.get('correct')
        if correct is None:
            correct_str = "N/A"
            correct_style = "dim"
        elif correct:
            correct_str = "✓"
            correct_style = "green"
        else:
            correct_str = "✗"
            correct_style = "red"
        
        table.add_row(
            data.get('task_id', 'N/A'),
            data.get('model', 'N/A'),
            data.get('provider', 'N/A'),
            f"{data.get('time_sec', 0):.2f}",
            f"[{success_style}]{success_str}[/{success_style}]",
            f"[{correct_style}]{correct_str}[/{correct_style}]"
        )
    
    console.print(table)


if __name__ == '__main__':
    main()
