"""Tests for health checking functionality."""

import pytest
import asyncio
from datetime import datetime

from vikdata.health import HealthChecker, HealthReporter
from vikdata import VikdataClient


@pytest.mark.asyncio
async def test_health_checker_no_checks():
    """Test health checker with no checks returns healthy."""
    checker = HealthChecker()
    result = await checker.check()

    assert result["status"] == "healthy"
    assert "timestamp" in result
    assert result["checks"] == {}


@pytest.mark.asyncio
async def test_health_checker_all_healthy():
    """Test health checker with all checks passing."""
    checker = HealthChecker()

    async def check_db():
        return True

    async def check_redis():
        return True

    checker.add_check("database", check_db)
    checker.add_check("redis", check_redis)

    result = await checker.check()

    assert result["status"] == "healthy"
    assert "database" in result["checks"]
    assert "redis" in result["checks"]
    assert result["checks"]["database"]["healthy"] is True
    assert result["checks"]["redis"]["healthy"] is True


@pytest.mark.asyncio
async def test_health_checker_degraded():
    """Test health checker with some checks failing."""
    checker = HealthChecker()

    async def check_db():
        return True

    async def check_redis():
        return False

    checker.add_check("database", check_db)
    checker.add_check("redis", check_redis)

    result = await checker.check()

    assert result["status"] == "degraded"
    assert result["checks"]["database"]["healthy"] is True
    assert result["checks"]["redis"]["healthy"] is False


@pytest.mark.asyncio
async def test_health_checker_unhealthy():
    """Test health checker with all checks failing."""
    checker = HealthChecker()

    async def check_db():
        return False

    async def check_redis():
        return False

    checker.add_check("database", check_db)
    checker.add_check("redis", check_redis)

    result = await checker.check()

    assert result["status"] == "unhealthy"
    assert result["checks"]["database"]["healthy"] is False
    assert result["checks"]["redis"]["healthy"] is False


@pytest.mark.asyncio
async def test_health_checker_exception_handling():
    """Test health checker handles exceptions in checks."""
    checker = HealthChecker()

    async def failing_check():
        raise RuntimeError("Check failed")

    checker.add_check("failing", failing_check)

    result = await checker.check()

    assert result["status"] == "unhealthy"
    assert "failing" in result["checks"]
    assert "error" in result["checks"]["failing"]


@pytest.mark.asyncio
async def test_health_checker_timeout():
    """Test health checker times out slow checks."""
    checker = HealthChecker()

    async def slow_check():
        await asyncio.sleep(10)  # Will timeout after 5 seconds
        return True

    checker.add_check("slow", slow_check)

    result = await checker.check()

    # Should mark as unhealthy due to timeout
    assert result["status"] == "unhealthy"
    assert result["checks"]["slow"]["healthy"] is False


@pytest.mark.asyncio
async def test_health_checker_remove_check():
    """Test removing a health check."""
    checker = HealthChecker()

    async def check_db():
        return True

    checker.add_check("database", check_db)
    result1 = await checker.check()
    assert "database" in result1["checks"]

    checker.remove_check("database")
    result2 = await checker.check()
    assert "database" not in result2["checks"]


@pytest.mark.asyncio
async def test_health_checker_get_status():
    """Test getting current status without running checks."""
    checker = HealthChecker()

    async def check_db():
        return True

    checker.add_check("database", check_db)
    await checker.check()

    status = checker.get_status()
    assert status == "healthy"


@pytest.mark.asyncio
async def test_health_checker_get_last_check_time():
    """Test getting last check time."""
    checker = HealthChecker()

    assert checker.get_last_check_time() is None

    async def check_db():
        return True

    checker.add_check("database", check_db)
    await checker.check()

    last_check = checker.get_last_check_time()
    assert last_check is not None
    assert isinstance(last_check, datetime)


@pytest.mark.asyncio
async def test_health_reporter_initialization():
    """Test health reporter initialization."""
    checker = HealthChecker()
    client = VikdataClient(base_url="http://localhost:8000", api_key="test-key")

    reporter = HealthReporter(
        health_checker=checker,
        service_id="service-123",
        client=client,
        interval=10.0,
    )

    assert reporter.health_checker == checker
    assert reporter.service_id == "service-123"
    assert reporter.interval == 10.0
    assert reporter._task is None
    assert reporter._running is False


@pytest.mark.asyncio
async def test_health_reporter_start_stop():
    """Test starting and stopping health reporter."""
    checker = HealthChecker()
    client = VikdataClient(base_url="http://localhost:8000", api_key="test-key")

    reporter = HealthReporter(
        health_checker=checker,
        service_id="service-123",
        client=client,
        interval=1.0,
    )

    await reporter.start()
    assert reporter._running is True
    assert reporter._task is not None

    await reporter.stop()
    assert reporter._running is False
