"""nikame test — First-class testing suite for NIKAME projects.

Automates venv creation, dependency installation, and pytest execution
with support for unit, integration, and e2e levels.
"""

from __future__ import annotations

import os
import subprocess
import sys
from pathlib import Path

import click

from nikame.utils.logger import console


@click.command()
@click.option("--unit", is_flag=True, help="Run unit tests only.")
@click.option("--integration", is_flag=True, help="Run integration tests.")
@click.option("--e2e", is_flag=True, help="Run end-to-end tests.")
@click.option("--coverage", is_flag=True, help="Run with coverage reporting.")
@click.option("--watch", is_flag=True, help="Watch for changes and re-run.")
@click.option(
    "--project-dir",
    type=click.Path(exists=True, path_type=Path),
    default=Path("."),
    help="Project directory to test.",
)
def test(
    unit: bool,
    integration: bool,
    e2e: bool,
    coverage: bool,
    watch: bool,
    project_dir: Path,
) -> None:
    """Run tests for the current NIKAME project."""
    console.print("[info]🚀 Starting NIKAME Test Suite...[/info]")

    # 1. Identify project root
    if not (project_dir / "app").exists():
        console.print("[error]✗ Error: 'app/' directory not found. Please run this command from the project root.[/error]")
        raise SystemExit(1)

    # 2. Ensure .venv exists
    venv_dir = project_dir / ".venv"
    if not venv_dir.exists():
        console.print("[info]Creating isolated .venv...[/info]")
        try:
            subprocess.run([sys.executable, "-m", "venv", str(venv_dir)], check=True)
        except subprocess.CalledProcessError as e:
            console.print(f"[error]✗ Failed to create venv: {e}[/error]")
            raise SystemExit(1)

    # 3. Determine python and pip paths
    if os.name == "nt":
        python_bin = venv_dir / "Scripts" / "python.exe"
        pip_bin = venv_dir / "Scripts" / "pip.exe"
        pytest_bin = venv_dir / "Scripts" / "pytest.exe"
    else:
        python_bin = venv_dir / "bin" / "python"
        pip_bin = venv_dir / "bin" / "pip"
        pytest_bin = venv_dir / "bin" / "pytest"

    # 4. Install dependencies if needed
    with console.status("[info]Checking dependencies...[/info]"):
        req_files = ["requirements.txt", "requirements-test.txt"]
        for req_file in req_files:
            req_path = project_dir / req_file
            if req_path.exists():
                try:
                    subprocess.run([str(pip_bin), "install", "-r", str(req_path)], check=True, capture_output=True)
                except subprocess.CalledProcessError as e:
                    console.print(f"[error]✗ Failed to install {req_file}: {e.stderr.decode()}[/error]")
                    raise SystemExit(1)

    # 5. Build pytest command
    cmd = [str(pytest_bin)]
    
    if watch:
        # Check if pytest-watch is installed
        try:
            subprocess.run([str(pip_bin), "install", "pytest-watch"], check=True, capture_output=True)
            ptw_bin = venv_dir / ("Scripts" if os.name == "nt" else "bin") / "ptw"
            cmd = [str(ptw_bin)]
        except subprocess.CalledProcessError:
            console.print("[warning]⚠ pytest-watch installation failed. Falling back to standard pytest.[/warning]")

    if unit:
        cmd.extend(["-m", "unit"])
    if integration:
        cmd.extend(["-m", "integration"])
    if e2e:
        cmd.extend(["-m", "e2e"])
    
    if coverage:
        cmd.extend(["--cov=app", "--cov-report=term-missing"])

    # Set PYTHONPATH to include the app directory
    env = os.environ.copy()
    env["PYTHONPATH"] = str(project_dir / "app")

    # 6. Run it
    console.print(f"[info]Running: {' '.join(cmd)}[/info]\n")
    try:
        subprocess.run(cmd, env=env, check=True)
        console.print("\n[success]✨ All tests passed! ✨[/success]")
    except subprocess.CalledProcessError:
        console.print("\n[error]✗ Test execution failed.[/error]")
        raise SystemExit(1)
    except FileNotFoundError:
        console.print("\n[error]✗ pytest not found in .venv. Ensure requirements-test.txt is correct.[/error]")
        raise SystemExit(1)
