"""
FastAPI router for tester tool.
"""

from pathlib import Path
from typing import Optional
from pydantic import BaseModel
from fastapi import APIRouter, HTTPException, Request
from fastapi.responses import HTMLResponse, PlainTextResponse, FileResponse
from fastapi.templating import Jinja2Templates

from .config import config, environments
from .core import (
    discover_tests,
    get_tests_tree,
    start_test_run,
    get_run_status,
    list_runs,
    TestStatus,
)
from .gherkin.parser import discover_features, extract_tags_from_features, get_feature_names, get_scenario_names
from .gherkin.sync import sync_features_from_album


router = APIRouter(prefix="/tools/tester", tags=["tester"])
templates = Jinja2Templates(directory=Path(__file__).parent / "templates")


class RunRequest(BaseModel):
    """Request to start a test run."""
    test_ids: Optional[list[str]] = None


class RunResponse(BaseModel):
    """Response after starting a test run."""
    run_id: str
    status: str


class TestResultResponse(BaseModel):
    """A single test result."""
    test_id: str
    name: str
    status: str
    duration: float
    error_message: Optional[str] = None
    traceback: Optional[str] = None
    artifacts: list[dict] = []


class RunStatusResponse(BaseModel):
    """Status of a test run."""
    run_id: str
    status: str
    total: int
    completed: int
    passed: int
    failed: int
    errors: int
    skipped: int
    current_test: Optional[str] = None
    results: list[TestResultResponse]
    duration: Optional[float] = None


@router.get("/", response_class=HTMLResponse)
def index(request: Request):
    """Render the test runner UI."""
    tests_tree = get_tests_tree()
    tests_list = discover_tests()

    return templates.TemplateResponse("index.html", {
        "request": request,
        "config": config,
        "tests_tree": tests_tree,
        "total_tests": len(tests_list),
    })


@router.get("/health")
def health():
    """Health check endpoint."""
    return {"status": "ok", "tool": "tester"}


@router.get("/filters", response_class=HTMLResponse)
def test_filters(request: Request):
    """Show filterable test view with multiple filter options."""
    return templates.TemplateResponse("filters.html", {
        "request": request,
        "config": config,
    })


@router.get("/filters_v2", response_class=HTMLResponse)
def test_filters_v2(request: Request):
    """Show Gherkin-driven filter view (v2 with pulse variables)."""
    return templates.TemplateResponse("filters_v2.html", {
        "request": request,
        "config": config,
    })


@router.get("/api/config")
def get_config():
    """Get current configuration."""
    api_key = config.get("CONTRACT_TEST_API_KEY", "")
    return {
        "url": config.get("CONTRACT_TEST_URL", ""),
        "has_api_key": bool(api_key),
        "api_key_preview": f"{api_key[:8]}..." if len(api_key) > 8 else "",
    }


@router.get("/api/environments")
def get_environments():
    """Get available test environments."""
    # Sanitize API keys - only return preview
    safe_envs = []
    for env in environments:
        safe_env = env.copy()
        api_key = safe_env.get("api_key", "")
        if api_key:
            safe_env["has_api_key"] = True
            safe_env["api_key_preview"] = f"{api_key[:8]}..." if len(api_key) > 8 else "***"
            del safe_env["api_key"]  # Don't send full key to frontend
        else:
            safe_env["has_api_key"] = False
            safe_env["api_key_preview"] = ""
        safe_envs.append(safe_env)

    return {"environments": safe_envs}


@router.post("/api/environment/select")
def select_environment(env_id: str):
    """Select a target environment for testing."""
    # Find the environment
    env = next((e for e in environments if e["id"] == env_id), None)
    if not env:
        raise HTTPException(status_code=404, detail=f"Environment {env_id} not found")

    # Update config (in memory for this session)
    config["CONTRACT_TEST_URL"] = env["url"]
    config["CONTRACT_TEST_API_KEY"] = env.get("api_key", "")

    return {
        "success": True,
        "environment": {
            "id": env["id"],
            "name": env["name"],
            "url": env["url"],
            "has_api_key": bool(env.get("api_key"))
        }
    }


@router.get("/api/tests")
def list_tests():
    """List all discovered tests."""
    tests = discover_tests()
    return {
        "total": len(tests),
        "tests": [
            {
                "id": t.id,
                "name": t.name,
                "module": t.module,
                "class_name": t.class_name,
                "method_name": t.method_name,
                "doc": t.doc,
            }
            for t in tests
        ],
    }


@router.get("/api/tests/tree")
def get_tree():
    """Get tests as a tree structure."""
    return get_tests_tree()


@router.post("/api/run", response_model=RunResponse)
def run_tests(request: RunRequest):
    """Start a test run."""
    run_id = start_test_run(request.test_ids)
    return RunResponse(run_id=run_id, status="running")


@router.get("/api/run/{run_id}", response_model=RunStatusResponse)
def get_run(run_id: str):
    """Get status of a test run (for polling)."""
    status = get_run_status(run_id)
    if not status:
        raise HTTPException(status_code=404, detail=f"Run {run_id} not found")

    duration = None
    if status.started_at:
        end_time = status.finished_at or __import__("time").time()
        duration = round(end_time - status.started_at, 2)

    return RunStatusResponse(
        run_id=status.run_id,
        status=status.status,
        total=status.total,
        completed=status.completed,
        passed=status.passed,
        failed=status.failed,
        errors=status.errors,
        skipped=status.skipped,
        current_test=status.current_test,
        duration=duration,
        results=[
            TestResultResponse(
                test_id=r.test_id,
                name=r.name,
                status=r.status.value,
                duration=round(r.duration, 3),
                error_message=r.error_message,
                traceback=r.traceback,
                artifacts=r.artifacts,
            )
            for r in status.results
        ],
    )


@router.get("/api/runs")
def list_all_runs():
    """List all test runs."""
    return {"runs": list_runs()}


@router.get("/api/artifact/{run_id}/{filename}")
def stream_artifact(run_id: str, filename: str):
    """
    Stream an artifact file (video, screenshot, trace).

    Similar to jira vein's attachment streaming endpoint.
    """
    # Get artifacts directory
    artifacts_dir = Path(__file__).parent / "artifacts"

    # Search for the artifact in all subdirectories
    for subdir in ["videos", "screenshots", "traces"]:
        artifact_path = artifacts_dir / subdir / run_id / filename
        if artifact_path.exists():
            # Determine media type
            if filename.endswith(".webm"):
                media_type = "video/webm"
            elif filename.endswith(".mp4"):
                media_type = "video/mp4"
            elif filename.endswith(".png"):
                media_type = "image/png"
            elif filename.endswith(".jpg") or filename.endswith(".jpeg"):
                media_type = "image/jpeg"
            elif filename.endswith(".zip"):
                media_type = "application/zip"
            else:
                media_type = "application/octet-stream"

            return FileResponse(
                path=artifact_path,
                media_type=media_type,
                filename=filename
            )

    # Not found
    raise HTTPException(status_code=404, detail=f"Artifact not found: {run_id}/{filename}")


@router.get("/api/artifacts/{run_id}")
def list_artifacts(run_id: str):
    """List all artifacts for a test run."""
    artifacts_dir = Path(__file__).parent / "artifacts"
    artifacts = []

    # Search in all artifact directories
    for subdir, artifact_type in [
        ("videos", "video"),
        ("screenshots", "screenshot"),
        ("traces", "trace")
    ]:
        run_dir = artifacts_dir / subdir / run_id
        if run_dir.exists():
            for artifact_file in run_dir.iterdir():
                if artifact_file.is_file():
                    artifacts.append({
                        "type": artifact_type,
                        "filename": artifact_file.name,
                        "size": artifact_file.stat().st_size,
                        "url": f"/tools/tester/api/artifact/{run_id}/{artifact_file.name}"
                    })

    return {"artifacts": artifacts}


@router.get("/api/features")
def list_features():
    """List all discovered Gherkin features."""
    features_dir = Path(__file__).parent / "features"
    features = discover_features(features_dir)

    return {
        "features": [
            {
                "name": f.name,
                "description": f.description,
                "file_path": f.file_path,
                "language": f.language,
                "tags": f.tags,
                "scenario_count": len(f.scenarios),
                "scenarios": [
                    {
                        "name": s.name,
                        "description": s.description,
                        "tags": s.tags,
                        "type": s.scenario_type,
                    }
                    for s in f.scenarios
                ]
            }
            for f in features
        ],
        "total": len(features)
    }


@router.get("/api/features/tags")
def list_feature_tags():
    """List all unique tags from Gherkin features."""
    features_dir = Path(__file__).parent / "features"
    features = discover_features(features_dir)
    tags = extract_tags_from_features(features)

    return {
        "tags": sorted(list(tags)),
        "total": len(tags)
    }


@router.post("/api/features/sync")
def sync_features():
    """Sync feature files from album/book/gherkin-samples/."""
    result = sync_features_from_album()
    return result
