"""
Service layer for system and security audit logging.
"""

from typing import Any
from uuid import UUID

from sqlalchemy.ext.asyncio import AsyncSession

from app.models.audit import AuditCategory, AuditSeverity
from app.repositories.audit_repository import AuditRepository
from app.repositories.lab_repository import LabRepository
from app.schemas.audit import AuditLogResponse, AuditMetricsResponse


class AuditService:
    """Business logic for system audit trail aggregation and retrieval."""

    def __init__(self, repo: AuditRepository | None = None) -> None:
        self.repo = repo or AuditRepository()
        self.lab_repo = LabRepository()

    async def list_logs(
        self,
        db: AsyncSession,
        lab_id: UUID | None = None,
        category: str | None = None,
        severity: str | None = None,
        search: str | None = None,
        limit: int = 50,
        offset: int = 0,
    ) -> tuple[list[AuditLogResponse], int]:
        """Fetch audit log entries matching filters."""
        if lab_id is None:
            lab_id = await self.lab_repo.get_default_lab_id(db)

        records, total = await self.repo.list_logs(
            db, lab_id=lab_id, category=category, severity=severity, search=search, limit=limit, offset=offset
        )
        return [AuditLogResponse.model_validate(r) for r in records], total

    async def get_metrics(self, db: AsyncSession, lab_id: UUID | None = None) -> AuditMetricsResponse:
        """Fetch aggregated telemetry metrics for audit dashboard."""
        if lab_id is None:
            lab_id = await self.lab_repo.get_default_lab_id(db)

        counts = await self.repo.get_metrics(db, lab_id)
        return AuditMetricsResponse(
            total_events=counts["total"],
            security_events=counts["security"],
            clinical_events=counts["clinical"],
            admin_events=counts["admin"],
            billing_events=counts["billing"],
        )

    async def record_event(
        self,
        db: AsyncSession,
        action: str,
        description: str,
        category: str = AuditCategory.ADMIN.value,
        severity: str = AuditSeverity.INFO.value,
        actor_name: str = "System Administrator",
        actor_role: str = "owner",
        actor_id: UUID | None = None,
        target_type: str | None = None,
        target_id: str | None = None,
        ip_address: str | None = "127.0.0.1",
        details: dict[str, Any] | None = None,
        lab_id: UUID | None = None,
    ) -> AuditLogResponse:
        """Record an explicit audit event."""
        if lab_id is None:
            lab_id = await self.lab_repo.get_default_lab_id(db)

        log = await self.repo.create_log(
            db,
            lab_id=lab_id,
            action=action,
            category=category,
            severity=severity,
            actor_name=actor_name,
            actor_role=actor_role,
            actor_id=actor_id,
            target_type=target_type,
            target_id=target_id,
            description=description,
            ip_address=ip_address,
            details=details,
        )
        return AuditLogResponse.model_validate(log)
