import logging

from fastapi import APIRouter, HTTPException, status
from neo4j import GraphDatabase
from neo4j.exceptions import Neo4jError, ServiceUnavailable
from pydantic import BaseModel
from slowapi import Limiter
from slowapi.util import get_remote_address

from app.core.config import get_settings

logger = logging.getLogger(__name__)
router = APIRouter(tags=["health"])
limiter = Limiter(key_func=get_remote_address)


class HealthResponse(BaseModel):
    """Response payload for health checks.

    Attributes:
        status: Overall service status.
        db: Database connectivity status.
    """

    status: str
    db: str


def _ping_neo4j() -> None:
    """Ping Neo4j using a lightweight query.

    Args:
        None.

    Raises:
        HTTPException: When Neo4j is unavailable or credentials are invalid.
    """
    settings = get_settings()
    driver = None
    try:
        driver = GraphDatabase.driver(
            settings.neo4j_uri,
            auth=(settings.neo4j_username, settings.neo4j_password),
        )
        with driver.session() as session:
            session.run("RETURN 1").consume()
        logger.info("Neo4j ping succeeded", extra={"db": "neo4j"})
    except (Neo4jError, ServiceUnavailable) as exc:
        logger.info("Neo4j ping failed", extra={"db": "neo4j"})
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail="Neo4j unavailable",
        ) from exc
    finally:
        if driver is not None:
            driver.close()


@router.get(
    "/health",
    response_model=HealthResponse,
    status_code=status.HTTP_200_OK,
)
@limiter.exempt
def health_check() -> HealthResponse:
    """Return service health status and database connectivity.

    Args:
        None.

    Returns:
        HealthResponse: Health status payload.

    Raises:
        HTTPException: When Neo4j is unavailable.
    """
    _ping_neo4j()
    return HealthResponse(status="ok", db="connected")
