package com.seer.teach.iot.admin.service.impl;

import cn.hutool.core.convert.Convert;
import com.alibaba.druid.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.seer.teach.iot.admin.convert.AdminBeatsConvert;
import com.seer.teach.iot.admin.convert.AdminVersionConvert;
import com.seer.teach.iot.admin.convert.AdminsDeviceConvert;
import com.seer.teach.iot.admin.req.AddBeatsReq;
import com.seer.teach.iot.admin.req.AddVersionReq;
import com.seer.teach.iot.admin.resp.APKDetailResp;
import com.seer.teach.iot.admin.resp.BeatVersionResp;
import com.seer.teach.iot.admin.resp.DeviceListResp;
import com.seer.teach.iot.admin.service.AdminVersionService;
import com.seer.teach.common.PageListBean;
import com.seer.teach.common.cache.DeviceMetricsCacheService;
import com.seer.teach.common.cache.dto.DeviceMetricDTO;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.enums.TvVersionCategoryEnum;
import com.seer.teach.common.exception.CommonException;
import com.seer.teach.common.service.CommonFileService;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.common.utils.PageConverterUtils;
import com.seer.teach.iot.common.uitls.IotUtils;
import com.seer.teach.iot.module.entity.BeatsEntity;
import com.seer.teach.iot.module.entity.DevicesEntity;
import com.seer.teach.iot.module.entity.IotVersionsEntity;
import com.seer.teach.iot.module.entity.UserDevicesEntity;
import com.seer.teach.iot.service.BeatsService;
import com.seer.teach.iot.service.DevicesService;
import com.seer.teach.iot.service.IotVersionsService;
import com.seer.teach.iot.service.UserDevicesService;
import com.seer.teach.user.api.UserInfoServiceApi;
import com.seer.teach.user.api.dto.UserDeviceDTO;
import com.seer.teach.user.api.dto.UserInfoDTO;
import lombok.RequiredArgsConstructor;
import net.dongliu.apk.parser.ApkFile;
import net.dongliu.apk.parser.bean.ApkMeta;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *
 * <p>
 *
 * </p >
 *
 * @author Captain
 * @since 2025-09-11 11:23
 */
@Service
@RequiredArgsConstructor
public class AdminVersionServiceImpl implements AdminVersionService {


    private final CommonFileService commonFileService;

    private final IotVersionsService iotVersionsService;

    private final BeatsService beatsService;

    private final UserInfoServiceApi userInfoServiceApi;

    private final UserDevicesService userDevicesService;

    private final DevicesService devicesService;

    private final DeviceMetricsCacheService deviceMetricsCacheService;

    private final RedisTemplate<String, String> redisTemplate;

    /**
     * 上传版本APK文件并获取APK详细信息
     *
     * @param file 要上传的APK文件
     * @return APKDetailResp 包含APK版本信息和上传地址的响应对象
     */
    @Override
    public APKDetailResp uploadVersionAPK(MultipartFile file) {
        File tempFile = null;
        try {
            // 上传APK文件并获取访问URL
            String url = commonFileService.uploadAPKFile(file);
            // 将MultipartFile转换为临时文件
            tempFile = IotUtils.toFile(file);
            // 解析APK文件详细信息
            APKDetailResp apkDetail = getAPKDetail(tempFile, url);
            return apkDetail;
        } finally {
            // 清理临时文件
            if (tempFile != null) {
                tempFile.delete();
            }
        }
    }

    /**
     * 添加版本信息
     *
     * @param params 添加版本请求参数，包含版本号、版本名称、下载地址等信息
     */
    @Override
    public void addVersion(AddVersionReq params) {
        // 将请求参数转换为版本实体对象
        IotVersionsEntity saveData = AdminVersionConvert.INSTANCE.toVersionEntity(params);

        // 查询当前最大的版本号记录，用于判断版本是否重复
        IotVersionsEntity entity = iotVersionsService.getOne(
                new LambdaQueryWrapper<IotVersionsEntity>()
                        .orderByDesc(IotVersionsEntity::getVersionCode)
                        .last("limit 1")
        );

        // 断言检查版本是否重复，如果存在相同版本则抛出异常
        AssertUtils.isNull(entity, ResultCodeEnum.VERSION_REPEAT);

        // 保存新的版本信息
        iotVersionsService.save(saveData);
    }

    /**
     * 添加内测版本信息（beats表示版本内测）
     *
     * @param params 内测设备列表和版本ID信息
     */
    @Override
    public void addBeats(AddBeatsReq params) {
        // 查询已存在的内测设备记录
        List<BeatsEntity> oldBeats = beatsService.list(new LambdaQueryWrapper<BeatsEntity>()
                .in(BeatsEntity::getDeviceId, params.getDeviceIds()));

        // 验证设备未参与内测，如果已存在则抛出异常
        AssertUtils.isEmpty(oldBeats, ResultCodeEnum.PLEASE_DELETE_BEATE);

        // 构造内测设备与版本的关联数据
        List<BeatsEntity> saveDatas = params.getDeviceIds().stream().map(deviceId ->
                        AdminBeatsConvert.INSTANCE.toBeatsEntity(deviceId, params.getVersionId()))
                .collect(Collectors.toList());

        // 批量保存内测设备版本信息
        beatsService.saveBatch(saveDatas);
    }


    /**
     * 获取节拍版本列表
     *
     * @return 节拍版本响应对象列表，当前实现返回空列表
     */
    @Override
    public List<BeatVersionResp> getBeatVersions() {
        List<IotVersionsEntity> list = iotVersionsService.list(new LambdaQueryWrapper<IotVersionsEntity>()
                .eq(IotVersionsEntity::getVersionCategory, TvVersionCategoryEnum.BETA.getCode()));
        return AdminVersionConvert.INSTANCE.toBeatVersionRespList(list);
    }

    /**
     * 删除指定ID的节拍数据
     *
     * @param ids 要删除的节拍数据ID列表
     */
    @Override
    public void deleteBeats(List<Integer> ids) {
        beatsService.remove(new LambdaUpdateWrapper<BeatsEntity>()
                .in(BeatsEntity::getDeviceId,ids));
    }

    /**
     * 获取设备版本列表
     *
     * @param page           分页页码
     * @param size           分页大小
     * @param studentAccount 学生账号
     * @return 设备列表响应数据的分页结果
     */
    @Override
    public PageListBean<DeviceListResp> versionList(Integer page, Integer size, String studentAccount) {
        Page<BeatsEntity> pageParm = new Page<>(page, size);
        LambdaQueryWrapper<BeatsEntity> beatsQueryWrapper = new LambdaQueryWrapper<>();
        if (!StringUtils.isEmpty(studentAccount)) {
            UserInfoDTO userInfo = userInfoServiceApi.getUserByMobile(studentAccount);
            Integer deviceId = userDevicesService.getDeviceIdByUserId(userInfo.getId());
            beatsQueryWrapper.eq(BeatsEntity::getDeviceId, deviceId);
        }
        Page<BeatsEntity> pageResult = beatsService.page(pageParm, beatsQueryWrapper);
        if (pageResult.getRecords().isEmpty()) {
            return PageConverterUtils.convertPageListBean(pageResult, list -> Collections.emptyList());
        }
        List<Integer> deviceIds = pageResult.getRecords().stream().map(BeatsEntity::getDeviceId).collect(Collectors.toList());
        List<DevicesEntity> devices = devicesService.listByIds(deviceIds);
        List<Integer> versionIds = devices.stream().map(DevicesEntity::getVersionId).collect(Collectors.toList());
        Map<Integer, Integer> versionMaps = iotVersionsService.listByIds(versionIds).stream()
                .collect(Collectors.toMap(IotVersionsEntity::getId, IotVersionsEntity::getVersionCode));
        //批量查询状态
        Map<String, DeviceMetricDTO> statusMap = deviceMetricsCacheService.getAllOnlineDevices();
        //批量查询用户和设备关系
        List<UserDevicesEntity> allRelList = userDevicesService.list(new LambdaQueryWrapper<UserDevicesEntity>()
                .in(UserDevicesEntity::getDeviceId, deviceIds));
        Map<Integer, Integer> deviceUserMap = allRelList.stream()
                .collect(Collectors.toMap(UserDevicesEntity::getDeviceId,
                        UserDevicesEntity::getUserId, (a, b) -> a));
        // 批量查询用户信息
        List<Integer> userIds = allRelList.stream().map(UserDevicesEntity::getUserId).collect(Collectors.toList());
        Map<Integer, UserDeviceDTO> userMap = userInfoServiceApi.listByIds(userIds).stream()
                .collect(Collectors.toMap(UserDeviceDTO::getId, u -> u));

        //组装响应
        List<DeviceListResp> respList = devices.stream().map(d -> {
            Integer userId = deviceUserMap.get(d.getId());
            UserDeviceDTO user = userMap.get(userId);
            DeviceListResp resp = AdminsDeviceConvert.INSTANCE.toDeviceListResp(d, user);
            resp.setStatus(statusMap.containsKey(d.getUnionId()) ? 0 : 1);
            resp.setVersionCode(versionMaps.get(d.getVersionId()));
            return resp;
        }).collect(Collectors.toList());
        return PageConverterUtils.convertPageListBean(pageParm, list -> respList);
    }

    /**
     * 获取APK文件的详细信息
     *
     * @param tempFile 临时APK文件
     * @param url      APK文件的访问地址
     * @return APKDetailResp 包含APK版本名、版本号和访问地址的响应对象
     */
    private APKDetailResp getAPKDetail(File tempFile, String url) {
        try {
            // 使用APK解析库获取APK元数据
            ApkMeta apkMeta = new ApkFile(tempFile).getApkMeta();
            // 构造APK详细信息响应对象
            return new APKDetailResp(apkMeta.getVersionName(), Convert.toInt(apkMeta.getVersionCode()), url);
        } catch (Exception e) {
            // APk文件解析异常时抛出通用异常
            throw new CommonException(ResultCodeEnum.APK_FILE_ERROR);
        }
    }

}
