from datetime import datetime
from typing import Any, Dict, Iterable, Optional

from sqlalchemy.ext.asyncio import AsyncSession

from src.core.errors import AccessDeniedException

# from src.domain.models import AuditLog, UserRole, Users
from src.db.models.audit_log import AuditLog
from src.db.models.role import UserRoleEnum
from src.db.models.app_user import AppUser

from src.repository.auditlog_repository import AuditLogRepository

from src.domain.schemas import AuditLog as AuditLogSchema


class AuditLogService:
    """Сервис для работы с журналом аудита."""

    def __init__(self, db: AsyncSession):
        self.db = db
        self.audit_repo = AuditLogRepository(db)

    async def get(self, audit_log_id: int, user: AppUser) -> Optional[AuditLog]:
        """Получение записи аудита по ID."""
        if not self._can_view_audit_logs(user):
            raise AccessDeniedException(
                "Недостаточно прав для просмотра журнала аудита"
            )

        return await self.audit_repo.get(audit_log_id)

    async def get_all(
        self,
        user: AppUser,
        limit: int | None = None,
        offset: int | None = None,
        user_id: int | None = None,
        org_unit_id: int | None = None,
        task_id: int | None = None,
        form_id: int | None = None,
        event_type: str | None = None,
        event: str | None = None,
        date_from: datetime | None = None,
        date_to: datetime | None = None,
    ) -> tuple[Iterable[AuditLog], int]:
        """Получение всех записей аудита с опциональной фильтрацией."""
        if not self._can_view_audit_logs(user):
            raise AccessDeniedException(
                "Недостаточно прав для просмотра журнала аудита"
            )

        return await self.audit_repo.get_all(
            limit=limit,
            offset=offset,
            user_id=user_id,
            org_unit_id=org_unit_id,
            task_id=task_id,
            form_id=form_id,
            event_type=event_type,
            date_from=date_from,
            date_to=date_to,
            event=event,
        )

    def _can_view_audit_logs(self, user: AppUser) -> bool:
        """Проверяет, может ли пользователь просматривать журнал аудита."""
        return user.role_id == UserRoleEnum.ADMIN.value

    def orm_log_to_response(self, log: AuditLog) -> AuditLogSchema:
        """Маппинг записи ORM audit_log в формат ответа API (entity, entity_id, action, at, payload_json).
        model_validate(orm) не подходит: в БД поля event_dt/event/event_type/event_data, в API — at/action/entity/entity_id; entity и entity_id из event_data JSON.
        """
        event_data: Optional[Dict[str, Any]] = getattr(log, "event_data", None) or {}
        entity = (
            event_data.get("entity_type") if isinstance(event_data, dict) else None
        ) or getattr(log, "event_type", "unknown")
        entity_id = (
            event_data.get("entity_id") if isinstance(event_data, dict) else None
        )
        if entity_id is not None and not isinstance(entity_id, int):
            try:
                entity_id = int(entity_id)
            except (TypeError, ValueError):
                entity_id = None
        action = getattr(log, "event", "")
        at = getattr(log, "event_dt", None)
        return AuditLogSchema(
            entity=entity,
            entity_id=entity_id,
            action=action,
            payload_json=event_data if isinstance(event_data, dict) else None,
            id=log.id,
            user_id=getattr(log, "user_id", None),
            at=at,
            user=getattr(log, "user", None),
        )
