"""Compliance test runner for GA4GH specifications."""

from __future__ import annotations

import asyncio
import time
import typing
from dataclasses import dataclass, field
from enum import Enum


class TestStatus(str, Enum):
    """Status of a compliance test."""

    PASS = "pass"
    FAIL = "fail"
    SKIP = "skip"
    ERROR = "error"


@dataclass
class TestResult:
    """Result of a single compliance test."""

    name: str
    status: TestStatus
    message: str = ""
    duration_ms: float = 0.0
    spec: str = ""
    endpoint: str = ""


@dataclass
class SuiteResult:
    """Result of running a compliance suite."""

    spec: str
    base_url: str
    results: list[TestResult] = field(default_factory=list)
    duration_ms: float = 0.0

    @property
    def total(self) -> int:
        return len(self.results)

    @property
    def passed(self) -> int:
        return sum(1 for r in self.results if r.status == TestStatus.PASS)

    @property
    def failed(self) -> int:
        return sum(1 for r in self.results if r.status == TestStatus.FAIL)

    @property
    def skipped(self) -> int:
        return sum(1 for r in self.results if r.status == TestStatus.SKIP)

    @property
    def errors(self) -> int:
        return sum(1 for r in self.results if r.status == TestStatus.ERROR)

    @property
    def success_rate(self) -> float:
        if self.total == 0:
            return 0.0
        return self.passed / self.total * 100


class ComplianceSuite:
    """Base class for GA4GH compliance test suites."""

    spec_name: str = ""
    spec_version: str = ""

    def __init__(self, base_url: str) -> None:
        self.base_url = base_url.rstrip("/")

    async def run(self) -> SuiteResult:
        """Run all tests in the suite."""
        start = time.monotonic()
        results: list[TestResult] = []

        for method_name in sorted(dir(self)):
            if not method_name.startswith("test_"):
                continue
            method = getattr(self, method_name)
            if not callable(method):
                continue

            test_start = time.monotonic()
            try:
                if asyncio.iscoroutinefunction(method):
                    result = await method()
                else:
                    result = method()
                if result is None:
                    result = TestResult(
                        name=method_name,
                        status=TestStatus.PASS,
                        spec=self.spec_name,
                    )
            except Exception as e:
                result = TestResult(
                    name=method_name,
                    status=TestStatus.ERROR,
                    message=str(e),
                    spec=self.spec_name,
                )
            result.duration_ms = (time.monotonic() - test_start) * 1000
            results.append(result)

        duration = (time.monotonic() - start) * 1000
        return SuiteResult(
            spec=self.spec_name,
            base_url=self.base_url,
            results=results,
            duration_ms=duration,
        )


# Registry of available compliance suites
_SUITE_REGISTRY: dict[str, type[ComplianceSuite]] = {}


def register_suite(
    spec_name: str,
) -> typing.Callable[[type[ComplianceSuite]], type[ComplianceSuite]]:
    """Decorator to register a compliance suite."""

    def decorator(cls: type[ComplianceSuite]) -> type[ComplianceSuite]:
        _SUITE_REGISTRY[spec_name] = cls
        return cls

    return decorator


def get_suite(spec_name: str) -> type[ComplianceSuite] | None:
    """Get a registered compliance suite by spec name."""
    return _SUITE_REGISTRY.get(spec_name)


def list_suites() -> list[str]:
    """List all registered compliance suite names."""
    return sorted(_SUITE_REGISTRY.keys())
