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

import com.alibaba.cloud.commons.lang.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.entity.CityEntity;
import com.seer.teach.common.entity.ProvinceEntity;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.service.RegionAddressService;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.common.utils.PageConverterUtils;
import com.seer.teach.iot.admin.convert.AdminDeviceModelConvert;
import com.seer.teach.iot.admin.convert.AdminsDeviceConvert;
import com.seer.teach.iot.admin.resp.*;
import com.seer.teach.iot.admin.service.AdminDevicesService;
import com.seer.teach.iot.common.dto.CityPercentageDTO;
import com.seer.teach.iot.common.uitls.IotUtils;
import com.seer.teach.iot.module.entity.DeviceModelsEntity;
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.DeviceModelsService;
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.GradeServiceApi;
import com.seer.teach.user.api.LevelServiceApi;
import com.seer.teach.user.api.UserExtendServiceApi;
import com.seer.teach.user.api.UserInfoServiceApi;
import com.seer.teach.user.api.dto.LevelDTO;
import com.seer.teach.user.api.dto.UserDeviceDTO;
import com.seer.teach.user.api.dto.UserExtendDTO;
import com.seer.teach.user.api.dto.UserInfoDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * </p >
 *
 * @author Captain
 * @since 2025-08-13 20:45
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class AdminDevicesServiceImpl implements AdminDevicesService {

    private final DevicesService devicesService;

    private final DeviceModelsService deviceModelsService;

    private final RegionAddressService regionAddressService;

    private final UserDevicesService userDevicesService;

    private final UserInfoServiceApi userInfoServiceApi;

    private final UserExtendServiceApi userExtendServiceApi;

    private final LevelServiceApi levelServiceApi;

    private final GradeServiceApi gradeServiceApi;

    private final IotVersionsService versionsService;

    private final DeviceMetricsCacheService deviceMetricsCacheService;

    /**
     * 获取设备仪表盘信息
     *
     * @return DeviceDashboardResp 设备仪表盘响应数据，包含在线设备数、今日活跃设备数和设备总数
     */
    @Override
    public DeviceDashboardResp info() {
        // 获取今日在线设备数量
        int onlineDevices = deviceMetricsCacheService.getAllOnlineDevices().size();
        // 计算今日活跃设备数（创建时间在今日范围内的设备）
        LocalDate today = LocalDate.now();
        LocalDateTime startOfDay = today.atStartOfDay();
        LocalDateTime endOfDay = today.atTime(LocalTime.MAX);
        long todayActive = devicesService.count(new LambdaQueryWrapper<DevicesEntity>()
                .ge(DevicesEntity::getCreateTime, startOfDay)
                .le(DevicesEntity::getCreateTime, endOfDay)
        );
        // 获取设备总数量
        long totalDevices = devicesService.count(new LambdaQueryWrapper<DevicesEntity>());
        // 转换为响应对象并返回
        return AdminsDeviceConvert.INSTANCE.toDeviceDashboardResp(onlineDevices, todayActive, totalDevices);
    }

    /**
     * 计算设备型号销售比例
     *
     * @return 设备型号销售比例响应列表，包含型号ID、型号名称、销售比例和销售数量
     */
    @Override
    public List<DeviceModelSaleResp> modelSalesRatio() {
        // 获取所有设备型号信息
        List<DeviceModelsEntity> models = deviceModelsService.list();
        // 按型号ID分组，便于后续查找
        Map<Integer, DeviceModelsEntity> modelGroups = models.stream()
                .collect(Collectors.toMap(DeviceModelsEntity::getId, Function.identity()));
        // 提取所有型号ID列表
        List<Integer> modelIds = models.stream().map(DeviceModelsEntity::getId)
                .collect(Collectors.toList());
        // 统计各型号设备数量
        List<Map<String, Object>> counts = devicesService.countDevicesByModel();
        // 构建设备型号ID与数量的映射关系
        Map<Integer, Integer> modelCountMap = counts.stream()
                .collect(Collectors.toMap(
                        m -> (Integer) m.get("model_id"),
                        m -> ((Long) m.get("count")).intValue()
                ));
        // 计算设备总数
        Integer totalDeviceCount = modelCountMap.values().stream()
                .mapToInt(Integer::intValue)
                .sum();
        // 计算各型号销售比例并转换为响应对象
        return modelIds.stream().map(modelId -> {
            DeviceModelsEntity model = modelGroups.get(modelId);
            Integer count = modelCountMap.get(modelId);
            BigDecimal ratio = IotUtils.calculateAccuracy(totalDeviceCount, count != null ? count : 0);
            return AdminDeviceModelConvert.INSTANCE.toDeviceModelSaleResp(
                    modelId,
                    model.getModel(),
                    IotUtils.formatAccuracyPercentage(ratio),
                    count != null ? count.toString() : "0"
            );
        }).collect(Collectors.toList());

    }

    @Override
    public List<DeviceDistributionResp> deviceDistribution(Integer provinceId) {
        List<CityEntity> citys = regionAddressService.getCitysByProvinceId(provinceId);
        // 1. 获取省份下所有城市ID
        List<Integer> cityIds = citys.stream().map(CityEntity::getId).collect(Collectors.toList());

        // 3. 批量查询城市信息，避免重复数据库访问
        Map<Integer, String> cityMap = citys.stream()
                .collect(Collectors.toMap(CityEntity::getId, CityEntity::getCity));

        // 2. 查询城市占比数据
        List<CityPercentageDTO> sqlResults = devicesService.selectCityPercentages(cityIds);
        return sqlResults.stream().map(sqlResult -> {
            String city = cityMap.get(sqlResult.getCityId());
            return new DeviceDistributionResp(city, sqlResult.getPercentage(), sqlResult.getDeviceCount());
        }).collect(Collectors.toList());
    }

    /**
     * 分页查询设备列表
     *
     * @param page           分页页码，从1开始
     * @param size           每页显示记录数
     * @param studentAccount 学生账号，用于筛选特定学生的设备
     * @return
     */
    @Override
    public PageListBean<DeviceListResp> listPage(Integer page, Integer size, String studentAccount) {
        Page<DevicesEntity> pageParm = new Page<>(page, size);
        LambdaQueryWrapper<DevicesEntity> wrapper = new LambdaQueryWrapper<>();
        //根据学生账号模糊查询
        if (StringUtils.isNotBlank(studentAccount)) {
            addChildrenBindDeviceQuery(studentAccount, wrapper);
        }
        //查询设备列表
        IPage<DevicesEntity> resultPage = devicesService.pageList(pageParm, wrapper);
        List<DevicesEntity> devices = resultPage.getRecords();
        if (devices.isEmpty()) {
            return PageConverterUtils.convertPageListBean(resultPage, list -> Collections.emptyList());
        }

        // 收集 Device Id
        List<Integer> deviceIds = devices.stream().map(DevicesEntity::getId).collect(Collectors.toList());
        List<Integer> versionIds = devices.stream().map(DevicesEntity::getVersionId).collect(Collectors.toList());
        Map<Integer, Integer> versionMaps = versionsService.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(resultPage, list -> respList);
    }

    /**
     * 添加子查询条件，用于查询绑定到指定学生账户的设备信息
     *
     * @param studentAccount 学生账户（手机号）
     * @param wrapper        设备实体查询条件包装器
     */
    private void addChildrenBindDeviceQuery(String studentAccount, LambdaQueryWrapper<DevicesEntity> wrapper) {
        // 根据学生手机号获取用户信息
        UserInfoDTO user = userInfoServiceApi.getUserByMobile(studentAccount);
        AssertUtils.notNull(user, ResultCodeEnum.USER_NOT_FOUND);

        // 查询用户绑定的设备信息
        UserDevicesEntity one = userDevicesService.getOne(new LambdaQueryWrapper<UserDevicesEntity>()
                .eq(UserDevicesEntity::getUserId, user.getId()));
        AssertUtils.notNull(one, ResultCodeEnum.USER_NOT_BIND_DEVICE);

        //获取设备ID，作为分页查询条件
        wrapper.in(DevicesEntity::getId, one.getDeviceId());
    }


    /**
     * 获取设备详情
     *
     * @param id
     * @return
     */
    @Override
    public DeviceDetailResp getDeviceDetailById(Integer id) {
        DevicesEntity devices = devicesService.getById(id);
        AssertUtils.notNull(devices, ResultCodeEnum.DEVICE_NOT_FOUND);
        Integer cityId = devices.getCityId();
        CityEntity city = regionAddressService.getCityById(cityId);
        ProvinceEntity province = regionAddressService.getProvinceById(city.getProvinceId());
        DeviceModelsEntity deviceModel = deviceModelsService.getById(devices.getModelId());
        Integer tvStatus = getDeviceOnlineStatus(devices.getUnionId());
        UserDevicesEntity userDevices = userDevicesService.getOne(new LambdaQueryWrapper<UserDevicesEntity>()
                .eq(UserDevicesEntity::getDeviceId, id));
        Integer userId = userDevices.getUserId();
        UserInfoDTO userInfo = userInfoServiceApi.getByUserId(userId);
        UserExtendDTO userExtend = userExtendServiceApi.getUserExtendById(userId);
        LevelDTO level = levelServiceApi.getLevelById(userExtend.getLevelId());
        String grade = gradeServiceApi.getById(userExtend.getGradeId());
        return AdminsDeviceConvert.INSTANCE.toDeviceDetailResp(
                devices,
                city,
                province,
                deviceModel,
                userInfo,
                level,
                grade,
                tvStatus);
    }

    /**
     * 判断某个设备是否在线
     *
     * @param deviceId 设备ID
     * @return 0=在线，1=离线
     */
    public int getDeviceOnlineStatus(String deviceId) {
        DeviceMetricDTO latestMetric = deviceMetricsCacheService.getLatestMetric(deviceId);
        return latestMetric == null ? 1 : 0;
    }

}
