"""
vr test command - Run tests for a voice agent project.
"""

import asyncio
import os
import subprocess

from pathlib import Path
from typing import Optional

import typer

from vr_cli.utils.utils import (
    console,
    print_success,
    print_error,
    print_info,
    print_warning,
    load_api_key,
)
from vr_cli.utils.config import API_BASE_URL
from vr_cli.utils.installer import VENV_DIR
from vr_cli.utils.agent_lock import load_agent_lock
from vr_cli.commands.validate import (
    ValidationResult,
    validate_handler,
    validate_voicerun_dir,
)


async def setup_test_environment(
    project_dir: Path,
    agent_id: Optional[str],
    environment: Optional[str],
    verbose: bool = False,
) -> bool:
    """Set up the test environment by installing dependencies and fetching secrets."""
    from vr_cli.utils.installer import load_module, _get_secrets_for_agent, configure_logging

    configure_logging(verbose)

    try:
        # Set environment variables for the installer
        api_key = load_api_key()
        if api_key:
            os.environ["VOICERUN_API_KEY"] = api_key
        os.environ["VOICERUN_API_URL"] = API_BASE_URL

        if environment:
            os.environ["ENVIRONMENT"] = environment

        # Load and install the module
        print_info("Installing project dependencies...")
        await load_module(agent_id or "local")

        # Fetch secrets if we have an agent ID and environment
        if agent_id and environment:
            print_info(f"Fetching secrets for environment: {environment}")
            await _get_secrets_for_agent(agent_id, environment)

        return True

    except Exception as e:
        print_error(f"Failed to set up test environment: {e}")
        return False


def run_pytest(
    project_dir: Path,
    test_path: Optional[str],
    verbose: bool,
    coverage: bool,
    extra_args: list[str],
) -> int:
    """Run pytest with the specified options."""
    # Use the global .voicerun venv Python
    venv_python = VENV_DIR / "bin" / "python"
    cmd = [str(venv_python), "-m", "pytest"]

    # Add test path or default to project directory
    if test_path:
        cmd.append(test_path)
    else:
        # Look for tests directory or test files
        tests_dir = project_dir / "tests"
        if tests_dir.exists():
            cmd.append(str(tests_dir))
        else:
            # Look for test_*.py files in project root
            test_files = list(project_dir.glob("test_*.py"))
            if test_files:
                cmd.extend([str(f) for f in test_files])
            else:
                cmd.append(str(project_dir))

    # Add options
    if verbose:
        cmd.append("-v")

    if coverage:
        cmd.extend(["--cov=.", "--cov-report=term-missing"])

    # Add extra arguments
    cmd.extend(extra_args)

    # Source the variables file if it exists
    variables_file = project_dir / ".variables.env"
    if variables_file.exists():
        print_info("Loading environment variables from .variables.env")
        # Read and set environment variables
        with open(variables_file, "r") as f:
            for line in f:
                line = line.strip()
                if line.startswith("export "):
                    # Parse: export KEY='value'
                    parts = line[7:].split("=", 1)
                    if len(parts) == 2:
                        key = parts[0]
                        value = parts[1].strip("'\"")
                        os.environ[key] = value

    # Run pytest
    print_info(f"Running: {' '.join(cmd)}")
    console.print()

    result = subprocess.run(cmd, cwd=project_dir)
    return result.returncode


def test(
    path: Optional[str] = typer.Argument(
        None,
        help="Path to test file or directory. Defaults to 'tests/' or test_*.py files.",
    ),
    environment: Optional[str] = typer.Option(
        None,
        "--environment",
        "-e",
        help="Environment to fetch secrets from (e.g., development, production).",
    ),
    verbose: bool = typer.Option(
        False,
        "--verbose",
        "-v",
        help="Run pytest in verbose mode.",
    ),
    coverage: bool = typer.Option(
        False,
        "--coverage",
        "-c",
        help="Run with coverage reporting.",
    ),
    skip_install: bool = typer.Option(
        False,
        "--skip-install",
        help="Skip dependency installation.",
    ),
    extra_args: Optional[list[str]] = typer.Argument(
        None,
        help="Additional arguments to pass to pytest.",
    ),
):
    """Run tests for the voice agent project.

    This command:
    1. Validates the project structure
    2. Installs project dependencies
    3. Optionally fetches secrets from the specified environment
    4. Runs pytest with the specified options

    Examples:
        vr test                     # Run all tests
        vr test tests/test_handler.py  # Run specific test file
        vr test -e development      # Run tests with development secrets
        vr test -v -c               # Run with verbose output and coverage
        vr test -- -k "test_name"   # Pass extra args to pytest
    """
    project_dir = Path.cwd()
    voicerun_dir = project_dir / ".voicerun"

    # Check if this is a voicerun project
    if not voicerun_dir.exists():
        print_error("Not a voicerun project (.voicerun directory not found)")
        print_info("Run 'vr init' to create a new project")
        raise typer.Exit(1)

    # Validate project structure
    print_info("Validating project structure...")
    result = ValidationResult()
    validate_handler(project_dir, result)
    validate_voicerun_dir(project_dir, result)

    if not result.is_valid:
        print_error("Project validation failed:")
        for check, error in result.failed:
            console.print(f"  [red]✗[/red] {check}: {error}")
        raise typer.Exit(1)

    print_success("Project structure valid")
    console.print()

    # Load agent lock to get agent ID
    agent_lock = load_agent_lock(voicerun_dir)
    agent_id = agent_lock.get("id") if agent_lock else None

    if environment and not agent_id:
        print_warning("No agent.lock found. Run 'vr push' first to fetch secrets from an environment.")
        environment = None

    # Set up test environment
    if not skip_install:
        print_info("Setting up test environment...")
        success = asyncio.run(setup_test_environment(
            project_dir,
            agent_id,
            environment,
            verbose,
        ))

        if not success:
            raise typer.Exit(1)

        print_success("Test environment ready")
        console.print()

    # Run pytest
    print_info("Running tests...")
    console.print()

    exit_code = run_pytest(
        project_dir,
        path,
        verbose,
        coverage,
        extra_args or [],
    )

    console.print()
    if exit_code == 0:
        print_success("All tests passed!")
    else:
        print_error(f"Tests failed with exit code {exit_code}")

    raise typer.Exit(exit_code)
