"""
操作日志CRUD操作
"""
from typing import Optional, List, Dict, Any
from datetime import datetime, timedelta
from sqlalchemy import select, and_, or_, func, desc
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.operation_log import OperationLog


class OperationLogCRUD:
    """操作日志CRUD类"""

    async def get(self, db: AsyncSession, log_id: int) -> Optional[OperationLog]:
        """
        根据ID获取操作日志

        Args:
            db: 数据库会话
            log_id: 日志ID

        Returns:
            OperationLog对象或None
        """
        result = await db.execute(
            select(OperationLog).where(OperationLog.id == log_id)
        )
        return result.scalar_one_or_none()

    async def get_multi(
        self,
        db: AsyncSession,
        *,
        skip: int = 0,
        limit: int = 100,
        operator_id: Optional[int] = None,
        operator_name: Optional[str] = None,
        module: Optional[str] = None,
        operation_type: Optional[str] = None,
        result: Optional[str] = None,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None,
        keyword: Optional[str] = None
    ) -> tuple[List[OperationLog], int]:
        """
        获取操作日志列表

        Args:
            db: 数据库会话
            skip: 跳过条数
            limit: 返回条数
            operator_id: 操作人ID
            operator_name: 操作人姓名
            module: 模块名称
            operation_type: 操作类型
            result: 操作结果
            start_time: 开始时间
            end_time: 结束时间
            keyword: 关键词

        Returns:
            (日志列表, 总数)
        """
        # 构建查询条件
        conditions = []

        if operator_id:
            conditions.append(OperationLog.operator_id == operator_id)

        if operator_name:
            conditions.append(OperationLog.operator_name.ilike(f"%{operator_name}%"))

        if module:
            conditions.append(OperationLog.module == module)

        if operation_type:
            conditions.append(OperationLog.operation_type == operation_type)

        if result:
            conditions.append(OperationLog.result == result)

        if start_time:
            conditions.append(OperationLog.created_at >= start_time)

        if end_time:
            conditions.append(OperationLog.created_at <= end_time)

        if keyword:
            conditions.append(
                or_(
                    OperationLog.url.ilike(f"%{keyword}%"),
                    OperationLog.params.ilike(f"%{keyword}%"),
                    OperationLog.error_msg.ilike(f"%{keyword}%")
                )
            )

        # 查询总数
        count_query = select(func.count(OperationLog.id))
        if conditions:
            count_query = count_query.where(and_(*conditions))
        total_result = await db.execute(count_query)
        total = total_result.scalar() or 0

        # 查询数据
        query = select(OperationLog)
        if conditions:
            query = query.where(and_(*conditions))
        query = query.order_by(desc(OperationLog.created_at))
        query = query.offset(skip).limit(limit)

        result = await db.execute(query)
        items = result.scalars().all()

        return list(items), total

    async def create(
        self,
        db: AsyncSession,
        *,
        obj_in: Dict[str, Any]
    ) -> OperationLog:
        """
        创建操作日志

        Args:
            db: 数据库会话
            obj_in: 创建数据

        Returns:
            OperationLog对象
        """
        db_obj = OperationLog(**obj_in)
        db.add(db_obj)
        await db.flush()
        await db.refresh(db_obj)
        return db_obj

    async def get_statistics(
        self,
        db: AsyncSession,
        *,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None
    ) -> Dict[str, Any]:
        """
        获取操作日志统计信息

        Args:
            db: 数据库会话
            start_time: 开始时间
            end_time: 结束时间

        Returns:
            统计信息
        """
        # 构建时间条件
        conditions = []
        if start_time:
            conditions.append(OperationLog.created_at >= start_time)
        if end_time:
            conditions.append(OperationLog.created_at <= end_time)

        where_clause = and_(*conditions) if conditions else None

        # 总数
        total_query = select(func.count(OperationLog.id))
        if where_clause:
            total_query = total_query.where(where_clause)
        total_result = await db.execute(total_query)
        total_count = total_result.scalar() or 0

        # 成功数
        success_query = select(func.count(OperationLog.id)).where(OperationLog.result == "success")
        if where_clause:
            success_query = success_query.where(where_clause)
        success_result = await db.execute(success_query)
        success_count = success_result.scalar() or 0

        # 失败数
        failed_count = total_count - success_count

        # 今日操作数
        today = datetime.utcnow().date()
        today_start = datetime.combine(today, datetime.min.time())
        today_query = select(func.count(OperationLog.id)).where(OperationLog.created_at >= today_start)
        today_result = await db.execute(today_query)
        today_count = today_result.scalar() or 0

        # 模块分布
        module_query = select(
            OperationLog.module,
            func.count(OperationLog.id).label('count')
        ).group_by(OperationLog.module)
        if where_clause:
            module_query = module_query.where(where_clause)
        module_result = await db.execute(module_query)
        module_distribution = [
            {"module": row[0], "count": row[1]}
            for row in module_result
        ]

        # 操作类型分布
        operation_query = select(
            OperationLog.operation_type,
            func.count(OperationLog.id).label('count')
        ).group_by(OperationLog.operation_type)
        if where_clause:
            operation_query = operation_query.where(where_clause)
        operation_result = await db.execute(operation_query)
        operation_distribution = [
            {"operation_type": row[0], "count": row[1]}
            for row in operation_result
        ]

        return {
            "total_count": total_count,
            "success_count": success_count,
            "failed_count": failed_count,
            "today_count": today_count,
            "module_distribution": module_distribution,
            "operation_distribution": operation_distribution,
        }

    async def delete_old_logs(
        self,
        db: AsyncSession,
        *,
        days: int = 90
    ) -> int:
        """
        删除旧日志

        Args:
            db: 数据库会话
            days: 保留天数

        Returns:
            删除的日志数量
        """
        cutoff_date = datetime.utcnow() - timedelta(days=days)

        # 查询要删除的日志
        result = await db.execute(
            select(OperationLog.id).where(OperationLog.created_at < cutoff_date)
        )
        ids_to_delete = [row[0] for row in result]

        if not ids_to_delete:
            return 0

        # 批量删除
        from sqlalchemy import delete
        delete_stmt = delete(OperationLog).where(OperationLog.id.in_(ids_to_delete))
        await db.execute(delete_stmt)

        return len(ids_to_delete)

    async def get_operator_top(
        self,
        db: AsyncSession,
        *,
        limit: int = 10,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None
    ) -> List[Dict[str, Any]]:
        """
        获取操作排行榜

        Args:
            db: 数据库会话
            limit: 返回条数
            start_time: 开始时间
            end_time: 结束时间

        Returns:
            操作排行列表
        """
        # 构建时间条件
        conditions = []
        if start_time:
            conditions.append(OperationLog.created_at >= start_time)
        if end_time:
            conditions.append(OperationLog.created_at <= end_time)

        query = select(
            OperationLog.operator_id,
            OperationLog.operator_name,
            func.count(OperationLog.id).label('count')
        ).group_by(
            OperationLog.operator_id,
            OperationLog.operator_name
        ).order_by(
            desc('count')
        ).limit(limit)

        if conditions:
            query = query.where(and_(*conditions))

        result = await db.execute(query)
        return [
            {
                "operator_id": row[0],
                "operator_name": row[1],
                "count": row[2]
            }
            for row in result
        ]


# 创建全局实例
operation_log_crud = OperationLogCRUD()
