import logging
import time

from ipware import get_client_ip
from user_agents import parse

from blog.documents import ELASTICSEARCH_ENABLED, ElaspedTimeDocumentManager

logger = logging.getLogger(__name__)


class OnlineMiddleware(object):
    """
    在线性能监控中间件

    这个中间件用于监控网站的性能指标，包括：
    - 页面渲染时间
    - 用户访问信息
    - 用户代理分析
    - IP地理位置（通过Elasticsearch geoip管道）

    继承自object，是Django中间件的标准写法
    """

    def __init__(self, get_response=None):
        """
        初始化中间件

        Args:
            get_response: Django的下一个中间件或视图函数
        """
        self.get_response = get_response
        super().__init__()

    def __call__(self, request):
        """
        中间件主处理逻辑

        这个方在每次请求时被调用，用于：
        1. 记录请求开始时间
        2. 执行后续中间件和视图
        3. 计算页面渲染时间
        4. 收集用户访问数据
        5. 将数据存储到Elasticsearch（如果启用）
        6. 在响应内容中插入加载时间

        Args:
            request: Django请求对象

        Returns:
            HttpResponse: 处理后的响应对象
        """
        # 记录请求开始时间，用于计算页面渲染时间
        start_time = time.time()

        # 调用后续中间件和视图函数，获取响应
        response = self.get_response(request)

        # 从请求头中获取用户代理字符串
        http_user_agent = request.META.get('HTTP_USER_AGENT', '')

        # 获取客户端IP地址（使用ipware库处理代理情况）
        ip, _ = get_client_ip(request)

        # 解析用户代理字符串，获取浏览器、设备等信息
        user_agent = parse(http_user_agent)

        # 只处理非流式响应（避免对大文件下载等操作进行监控）
        if not response.streaming:
            try:
                # 计算页面渲染总时间（秒）
                cast_time = time.time() - start_time

                # 如果启用了Elasticsearch，记录性能数据
                if ELASTICSEARCH_ENABLED:
                    # 将时间转换为毫秒并保留2位小数
                    time_taken = round((cast_time) * 1000, 2)

                    # 获取请求的URL路径
                    url = request.path

                    # 导入时区模块，获取当前时间
                    from django.utils import timezone

                    # 创建性能监控记录到Elasticsearch
                    ElaspedTimeDocumentManager.create(
                        url=url,  # 请求URL
                        time_taken=time_taken,  # 耗时（毫秒）
                        log_datetime=timezone.now(),  # 记录时间
                        useragent=user_agent,  # 用户代理信息
                        ip=ip  # 客户端IP
                    )

                # 在响应内容中替换加载时间占位符
                # 将<!!LOAD_TIMES!!>替换为实际的加载时间（取前5位）
                response.content = response.content.replace(
                    b'<!!LOAD_TIMES!!>', str.encode(str(cast_time)[:5]))

            except Exception as e:
                # 记录中间件执行过程中的任何错误
                logger.error("Error OnlineMiddleware: %s" % e)

        # 返回处理后的响应
        return response
