from datetime import datetime
from typing import Optional, List
from uuid import UUID

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

from app.domain.schemas.audit import AuditLogResponse
from app.infra.db.metadb import models


class AuditRepository:
    """审计日志数据访问层（system_hub）"""

    def __init__(self, session: AsyncSession):
        self.session = session

    async def create_log(
        self,
        action: str,
        user_id: Optional[UUID] = None,
        project_id: Optional[UUID] = None,
        resource_type: Optional[str] = None,
        resource_id: Optional[str] = None,
        ip_address: Optional[str] = None,
        request_method: Optional[str] = None,
        request_path: Optional[str] = None,
        request_data: Optional[dict] = None,
        response_status: Optional[int] = None,
    ) -> AuditLogResponse:
        log = models.AuditLog(
            user_id=user_id,
            project_id=project_id,
            action=action,
            resource_type=resource_type,
            resource_id=resource_id,
            ip_address=ip_address,
            request_method=request_method,
            request_path=request_path,
            request_data=request_data,
            response_status=response_status,
            timestamp=datetime.utcnow(),
        )
        self.session.add(log)
        await self.session.commit()
        await self.session.refresh(log)
        return AuditLogResponse.model_validate(log)

    async def get_logs(
        self,
        user_id: Optional[UUID] = None,
        project_id: Optional[UUID] = None,
        action: Optional[str] = None,
        resource_type: Optional[str] = None,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None,
        skip: int = 0,
        limit: int = 100,
    ) -> List[AuditLogResponse]:
        conditions = []
        if user_id is not None:
            conditions.append(models.AuditLog.user_id == user_id)
        if project_id is not None:
            conditions.append(models.AuditLog.project_id == project_id)
        if action:
            conditions.append(models.AuditLog.action == action)
        if resource_type:
            conditions.append(models.AuditLog.resource_type == resource_type)
        if start_time:
            conditions.append(models.AuditLog.timestamp >= start_time)
        if end_time:
            conditions.append(models.AuditLog.timestamp <= end_time)

        stmt = (
            select(models.AuditLog)
            .where(*conditions)
            .order_by(models.AuditLog.timestamp.desc())
            .offset(skip)
            .limit(limit)
        )
        result = await self.session.execute(stmt)
        return [
            AuditLogResponse.model_validate(log)
            for log in result.scalars().all()
        ]

    async def get_log_count(
        self,
        user_id: Optional[UUID] = None,
        project_id: Optional[UUID] = None,
        action: Optional[str] = None,
        resource_type: Optional[str] = None,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None,
    ) -> int:
        conditions = []
        if user_id is not None:
            conditions.append(models.AuditLog.user_id == user_id)
        if project_id is not None:
            conditions.append(models.AuditLog.project_id == project_id)
        if action:
            conditions.append(models.AuditLog.action == action)
        if resource_type:
            conditions.append(models.AuditLog.resource_type == resource_type)
        if start_time:
            conditions.append(models.AuditLog.timestamp >= start_time)
        if end_time:
            conditions.append(models.AuditLog.timestamp <= end_time)

        stmt = select(func.count()).select_from(models.AuditLog).where(*conditions)
        result = await self.session.execute(stmt)
        return int(result.scalar() or 0)
