import uuid
from collections.abc import Sequence
from typing import Any

from sqlalchemy import delete, func, select
from sqlalchemy.ext.asyncio import AsyncSession

from src.domain.entities import AuditLogEntity
from src.domain.interfaces import IAuditLogRepository
from src.infrastructure.database.models import AuditLogModel


def _model_to_entity(m: AuditLogModel) -> AuditLogEntity:
    return AuditLogEntity(
        id=m.id,
        actor_id=m.actor_id,
        actor_type=m.actor_type,
        action=m.action,
        resource_type=m.resource_type,
        resource_id=m.resource_id,
        old_value=m.old_value,
        new_value=m.new_value,
        ip_address=m.ip_address,
        user_agent=m.user_agent,
        request_id=m.request_id,
        created_at=m.created_at,
    )


class AuditLogRepository(IAuditLogRepository):
    def __init__(self, session: AsyncSession) -> None:
        self._session = session

    async def add(self, entity: AuditLogEntity) -> AuditLogEntity:
        model = AuditLogModel(
            actor_id=entity.actor_id,
            actor_type=entity.actor_type,
            action=entity.action,
            resource_type=entity.resource_type,
            resource_id=entity.resource_id,
            old_value=entity.old_value,
            new_value=entity.new_value,
            ip_address=entity.ip_address,
            user_agent=entity.user_agent,
            request_id=entity.request_id,
        )
        self._session.add(model)
        await self._session.flush()
        return _model_to_entity(model)

    async def list_logs(
        self,
        *,
        actor_id: uuid.UUID | None = None,
        action: str | None = None,
        resource_type: str | None = None,
        offset: int = 0,
        limit: int = 50,
    ) -> tuple[Sequence[AuditLogEntity], int]:
        filters: list[Any] = []
        if actor_id:
            filters.append(AuditLogModel.actor_id == actor_id)
        if action:
            filters.append(AuditLogModel.action == action)
        if resource_type:
            filters.append(AuditLogModel.resource_type == resource_type)

        count_stmt = select(func.count()).select_from(AuditLogModel)
        if filters:
            count_stmt = count_stmt.where(*filters)
        total = (await self._session.execute(count_stmt)).scalar() or 0

        stmt = select(AuditLogModel).order_by(AuditLogModel.created_at.desc()).offset(offset).limit(limit)
        if filters:
            stmt = stmt.where(*filters)
        result = await self._session.execute(stmt)
        models = result.scalars().all()
        return [_model_to_entity(m) for m in models], total
