# Create your views here.
import datetime
import itertools
import json
import logging
from datetime import timezone
from itertools import groupby

import django
import requests
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.http import JsonResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt

# 导入当前应用的模型，用于在视图中操作数据库
from .models import OwnTrackLog

# 获取一个 logger 实例，用于记录日志信息（如请求、错误等）
logger = logging.getLogger(__name__)


# 视图函数：接收并处理 OwnTracks 客户端上传的位置日志数据
# 使用 @csrf_exempt 装饰器免除 CSRF 验证，因为客户端可能无法提供 CSRF token
# 该函数预期接收 JSON 格式的 POST 请求
@csrf_exempt
def manage_owntrack_log(request):
    try:
        # 读取请求体的原始数据，并解码为 UTF-8 字符串，然后解析为 Python 字典
        s = json.loads(request.read().decode('utf-8'))
        # 从解析后的数据中提取 tid（用户/设备标识）、lat（纬度）、lon（经度）
        tid = s['tid']
        lat = s['lat']
        lon = s['lon']

        # 记录一条 INFO 级别的日志，包含接收到的位置信息
        logger.info(
            'tid:{tid}.lat:{lat}.lon:{lon}'.format(
                tid=tid, lat=lat, lon=lon))

        # 验证提取的数据是否都存在（非空）
        if tid and lat and lon:
            # 创建一个新的 OwnTrackLog 模型实例
            m = OwnTrackLog()
            # 将接收到的数据赋值给模型字段
            m.tid = tid
            m.lat = lat
            m.lon = lon
            # 保存到数据库（creation_time 会自动使用默认值 now）
            m.save()
            # 返回 HTTP 响应 'ok'，表示数据接收和保存成功
            return HttpResponse('ok')
        else:
            # 如果数据不完整，返回 'data error'
            return HttpResponse('data error')
    except Exception as e:
        # 捕获任何异常，记录错误日志，并返回 'error' 响应
        logger.error(e)
        return HttpResponse('error')


# 视图函数：渲染显示地图的 HTML 页面
# 使用 @login_required 装饰器，确保只有登录用户才能访问
@login_required
def show_maps(request):
    # 进一步检查用户是否为超级用户（管理员）
    if request.user.is_superuser:
        # 获取当前 UTC 日期，作为默认日期
        defaultdate = str(datetime.datetime.now(timezone.utc).date())
        # 从 GET 请求参数中获取 'date'，如果不存在则使用默认日期
        date = request.GET.get('date', defaultdate)
        # 构造模板上下文，将日期传递给前端
        context = {
            'date': date
        }
        # 使用指定的 HTML 模板渲染响应
        return render(request, 'owntracks/show_maps.html', context)
    else:
        # 如果不是超级用户，返回 403 禁止访问
        from django.http import HttpResponseForbidden
        return HttpResponseForbidden()


# 视图函数：渲染显示有轨迹记录的日期列表页面
# 使用 @login_required 装饰器，确保只有登录用户才能访问
@login_required
def show_log_dates(request):
    # 查询所有 OwnTrackLog 记录的 creation_time 字段值
    dates = OwnTrackLog.objects.values_list('creation_time', flat=True)
    # 将 datetime 对象转换为 'YYYY-MM-DD' 格式的字符串，并去重、排序
    results = list(sorted(set(map(lambda x: x.strftime('%Y-%m-%d'), dates))))

    # 构造模板上下文，将日期列表传递给前端
    context = {
        'results': results
    }
    # 使用指定的 HTML 模板渲染响应
    return render(request, 'owntracks/show_log_dates.html', context)


# 辅助函数：将 GPS 坐标（WGS-84）批量转换为高德地图坐标系（GCJ-02）
# 由于高德 API 有数量限制，此处每次处理最多 30 个点
# 注意：此函数在 get_datas 中被注释掉，当前未使用
def convert_to_amap(locations):
    convert_result = []  # 存储转换后的坐标结果
    it = iter(locations)  # 创建一个迭代器

    # 每次从迭代器中取出最多 30 个位置点
    item = list(itertools.islice(it, 30))
    while item:
        # 将每个点的经度和纬度拼接成 "lon,lat" 字符串，用分号连接成一个列表
        datas = ';'.join(
            set(map(lambda x: str(x.lon) + ',' + str(x.lat), item)))

        # 高德坐标转换 API 的固定参数
        key = '8440a376dfc9743d8924bf0ad141f28e'
        api = 'http://restapi.amap.com/v3/assistant/coordinate/convert'
        # 构造请求参数
        query = {
            'key': key,
            'locations': datas,
            'coordsys': 'gps'  # 指定原始坐标系为 GPS（WGS-84）
        }
        # 发送 GET 请求到高德 API
        rsp = requests.get(url=api, params=query)
        # 解析 API 返回的 JSON 数据
        result = json.loads(rsp.text)
        # 如果返回结果包含转换后的坐标，则添加到结果列表
        if "locations" in result:
            convert_result.append(result['locations'])
        # 继续处理下一批最多 30 个点
        item = list(itertools.islice(it, 30))

    # 将所有批次的转换结果合并成一个以分号分隔的字符串并返回
    return ";".join(convert_result)


# 视图函数：返回指定日期的位置轨迹数据，供前端地图使用
# 返回 JSON 格式的数据，通常由 AJAX 调用
# 使用 @login_required 装饰器，确保只有登录用户才能访问
@login_required
def get_datas(request):
    # 获取当前 UTC 时间
    now = django.utils.timezone.now().replace(tzinfo=timezone.utc)
    # 构造查询日期的起始时间（当天 00:00:00 UTC）
    querydate = django.utils.timezone.datetime(
        now.year, now.month, now.day, 0, 0, 0)

    # 如果请求中包含 'date' 参数，则使用该参数指定的日期
    if request.GET.get('date', None):
        # 解析 'YYYY-MM-DD' 格式的日期字符串
        date = list(map(lambda x: int(x), request.GET.get('date').split('-')))
        querydate = django.utils.timezone.datetime(
            date[0], date[1], date[2], 0, 0, 0)

    # 计算查询结束时间（起始时间 + 1 天）
    nextdate = querydate + datetime.timedelta(days=1)

    # 查询指定日期范围内（当天）的所有位置记录
    models = OwnTrackLog.objects.filter(
        creation_time__range=(querydate, nextdate))

    # 初始化结果列表
    result = list()

    # 如果查询到记录，则按 tid（用户/设备）分组处理
    if models and len(models):
        for tid, item in groupby(
                # 先按 tid 排序，以便 groupby 正确分组
                sorted(models, key=lambda k: k.tid),
                # 指定分组依据为 tid
                key=lambda k: k.tid):

            # 为每个 tid 创建一个数据字典
            d = dict()
            d["name"] = tid  # 记录设备/用户名称
            paths = list()  # 存储该设备的轨迹点序列

            # 方案一（当前启用）：直接使用原始 GPS 坐标
            # 遍历该设备当天的所有位置点，按时间排序
            for location in sorted(item, key=lambda x: x.creation_time):
                # 将每个点的经度和纬度作为字符串列表添加到 paths
                paths.append([str(location.lon), str(location.lat)])

            # # 方案二（注释中）：使用高德转换后的坐标
            # # 先转换坐标，然后解析
            # locations = convert_to_amap(
            #     sorted(item, key=lambda x: x.creation_time))
            # for i in locations.split(';'):
            #     paths.append(i.split(','))

            # 将轨迹点列表赋值给字典的 "path" 键
            d["path"] = paths
            # 将该设备的轨迹数据添加到总结果列表
            result.append(d)

    # 将结果列表序列化为 JSON 并返回
    # safe=False 允许返回非字典类型的对象（如列表）
    return JsonResponse(result, safe=False)