#!/usr/bin/env python
# @Project : DjangoBaseAi
# @File    : operation_log.py
# @Author  : cx
# @Time    : 11/2/2025
# @Desc    :
import logging
import os
from urllib.parse import quote

from django.conf import settings
from django.db.models import Count
from django.http import StreamingHttpResponse
from rest_framework.decorators import action

from django_base_ai.system.models import Apps, OperationLog
from django_base_ai.utils.json_response import DetailResponse, ErrorResponse
from django_base_ai.utils.permission import AdminPermission
from django_base_ai.utils.serializers import CustomModelSerializer
from django_base_ai.utils.viewset import CustomModelViewSet

logger = logging.getLogger(__name__)


class OperationLogSerializer(CustomModelSerializer):
    """
    日志-序列化器
    """

    class Meta:
        model = OperationLog
        fields = "__all__"
        read_only_fields = ["id"]


class OperationLogCreateUpdateSerializer(CustomModelSerializer):
    """
    操作日志  创建/更新时的列化器
    """

    class Meta:
        model = OperationLog
        fields = "__all__"


class ExportOperationLogSerializer(CustomModelSerializer):
    """
    操作日志  创建/更新时的列化器
    """

    class Meta:
        model = OperationLog
        fields = "__all__"


class OperationLogViewSet(CustomModelViewSet):
    """
    操作日志接口
    list:查询
    create:新增
    update:修改
    retrieve:单例
    destroy:删除
    """

    queryset = OperationLog.objects.order_by("-create_datetime")
    serializer_class = OperationLogSerializer
    search_fields = ["appid", "request_modular", "request_ip", "response_code"]
    # 导出
    export_field_label = {
        "appid": "应用id",
        "creator_name": "操作人",
        "request_modular": "请求模块",
        "request_path": "请求地址",
        "request_body": "请求参数",
        "request_method": "请求方式",
        "request_msg": "操作说明",
        "request_ip": "请求ip地址",
        "request_browser": "请求浏览器",
        "response_code": "响应状态码",
        "request_os": "操作系统",
        "json_result": "返回信息",
    }
    export_serializer_class = ExportOperationLogSerializer

    @action(methods=["get"], detail=False)
    def usage_amount(self, request, *args, **kwargs):
        """
        使用量统计
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        Apps.objects.all()
        operation_log_result = OperationLog.objects.values("appid").annotate(count=Count("id"))
        operation_action_result = OperationLog.objects.values("request_method").annotate(count=Count("id"))
        operation_code_result = OperationLog.objects.values("response_code").annotate(count=Count("id"))
        print(operation_log_result)
        print(operation_action_result)
        print(operation_code_result)
        return DetailResponse([])

    def file_iterator(self, filename, chunk_size=512):
        """
        文件迭代器，用于流式下载
        """
        with open(filename, "rb") as f:
            while True:
                c = f.read(chunk_size)
                if c:
                    yield c
                else:
                    break

    @action(methods=["get"], detail=False)
    def analyze_logs(self, request, *args, **kwargs):
        """
        分析日志文件中的报错内容
        提供日志文件错误统计和分析功能
        """
        import re
        from collections import Counter, defaultdict
        from datetime import datetime

        # 获取查询参数
        log_type = request.GET.get("log_type", "error")  # error 或 server
        start_date = request.GET.get("start_date")
        end_date = request.GET.get("end_date")
        error_level = request.GET.get("error_level", "ERROR")  # ERROR, WARNING, INFO
        limit = int(request.GET.get("limit", 100))  # 返回记录数限制

        # 构建日志文件路径
        logs_dir = os.path.join(settings.BASE_DIR, "logs")
        if log_type == "error":
            log_file_path = os.path.join(logs_dir, "error.log")
        else:
            log_file_path = os.path.join(logs_dir, "server.log")

        # 检查文件是否存在
        if not os.path.exists(log_file_path):
            return ErrorResponse(msg=f"日志文件不存在: {log_type}.log")

        # 解析日志文件
        error_logs = []
        error_patterns = []
        error_counts = Counter()
        module_counts = Counter()
        time_counts = defaultdict(int)

        try:
            with open(log_file_path, encoding="utf-8") as f:
                lines = f.readlines()

            current_error = None

            for line_num, line in enumerate(lines, 1):
                line = line.strip()
                if not line:
                    continue

                # 匹配日志格式: [时间][模块][级别] 消息
                log_match = re.match(r"\[([^\]]+)\]\[([^\]]+)\] \[([^\]]+)\] (.+)", line)

                if log_match:
                    timestamp_str, module, level, message = log_match.groups()

                    # 解析时间
                    try:
                        timestamp = datetime.strptime(timestamp_str, "%Y-%m-%d %H:%M:%S,%f")
                    except ValueError:
                        try:
                            timestamp = datetime.strptime(timestamp_str, "%Y-%m-%d %H:%M:%S")
                        except ValueError:
                            timestamp = None

                    # 过滤时间范围
                    if start_date and timestamp:
                        try:
                            start_dt = datetime.strptime(start_date, "%Y-%m-%d")
                            if timestamp.date() < start_dt.date():
                                continue
                        except ValueError:
                            pass

                    if end_date and timestamp:
                        try:
                            end_dt = datetime.strptime(end_date, "%Y-%m-%d")
                            if timestamp.date() > end_dt.date():
                                continue
                        except ValueError:
                            pass

                    # 处理错误级别
                    if level == error_level:
                        # 保存当前错误
                        if current_error:
                            error_logs.append(current_error)

                        current_error = {
                            "timestamp": timestamp_str,
                            "module": module,
                            "level": level,
                            "message": message,
                            "line_number": line_num,
                            "stack_trace": [],
                        }

                        # 统计
                        error_counts[message] += 1
                        module_counts[module] += 1
                        if timestamp:
                            time_counts[timestamp.strftime("%Y-%m-%d")] += 1

                    # 处理堆栈跟踪
                    elif current_error and (line.startswith("  File ") or line.startswith("Traceback")):
                        current_error["stack_trace"].append(line)

                # 处理多行错误消息
                elif current_error and not line.startswith("["):
                    current_error["message"] += " " + line

            # 添加最后一个错误
            if current_error:
                error_logs.append(current_error)

        except Exception as e:
            return ErrorResponse(msg=f"读取日志文件失败: {str(e)}")

        # 限制返回记录数
        error_logs = error_logs[-limit:] if limit > 0 else error_logs

        # 分析错误模式
        error_patterns = []
        for error_msg, count in error_counts.most_common(10):
            # 提取错误模式（去除具体参数）
            pattern = re.sub(r"\d+", "N", error_msg)  # 数字替换为N
            pattern = re.sub(r"[a-f0-9]{8,}", "HASH", pattern)  # 哈希值替换
            pattern = re.sub(r"/[^\s]+", "/PATH", pattern)  # 路径替换
            error_patterns.append({"pattern": pattern, "count": count, "example": error_msg})

        # 构建返回数据
        result_data = {
            "log_file": f"{log_type}.log",
            "summary": {
                "total_errors": len(error_logs),
                "unique_error_types": len(error_counts),
                "top_modules": dict(module_counts.most_common(5)),
                "date_range": {
                    "start": min(time_counts.keys()) if time_counts else None,
                    "end": max(time_counts.keys()) if time_counts else None,
                },
            },
            "error_patterns": error_patterns,
            "module_statistics": [
                {"module": module, "count": count} for module, count in module_counts.most_common(10)
            ],
            "time_statistics": dict(time_counts),
            "recent_errors": [
                {
                    "timestamp": log["timestamp"],
                    "module": log["module"],
                    "level": log["level"],
                    "message": log["message"],
                    "line_number": log["line_number"],
                    "stack_trace": log["stack_trace"][:5],  # 只返回前5行堆栈
                }
                for log in error_logs[-20:]  # 最近20条错误
            ],
        }

        return DetailResponse(data=result_data)

    @action(methods=["get"], detail=False, permission_classes=[AdminPermission])
    def download_logs(self, request, *args, **kwargs):
        """
        管理员下载日志文件
        只有管理员可以下载logs文件夹里面的日志文件
        """
        log_filename = request.GET.get("filename", "server.log")

        # 验证文件名，防止路径遍历攻击
        if not log_filename or log_filename not in ["server.log", "error.log"]:
            return ErrorResponse(msg="无效的日志文件名")

        # 构建日志文件路径
        logs_dir = os.path.join(settings.BASE_DIR, "logs")
        log_file_path = os.path.join(logs_dir, log_filename)

        # 检查文件是否存在
        if not os.path.exists(log_file_path):
            return ErrorResponse(msg="日志文件不存在")

        # 检查文件是否可读
        if not os.access(log_file_path, os.R_OK):
            return ErrorResponse(msg="无法读取日志文件")

        # 设置响应头
        response = StreamingHttpResponse(self.file_iterator(log_file_path))
        response["Content-Type"] = "application/octet-stream"
        response["Content-Disposition"] = f'attachment; filename="{quote(log_filename)}"'

        return response
