package com.pig4cloud.pig.marketing.service.impl;


import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.common.core.util.ip.IPUtils;
import com.pig4cloud.pig.marketing.api.dto.MktMgmtPushRecordSaveDTO;
import com.pig4cloud.pig.marketing.api.dto.mongo.*;
import com.pig4cloud.pig.marketing.api.entity.mongo.Device;
import com.pig4cloud.pig.marketing.api.entity.mongo.Message;
import com.pig4cloud.pig.marketing.api.service.MktMgmtHandPushService;
import com.pig4cloud.pig.marketing.api.vo.mongo.*;
import com.pig4cloud.pig.marketing.config.UserStatisticsConfig;
import com.pig4cloud.pig.marketing.repository.MessageRepository;
import com.pig4cloud.pig.marketing.service.MktMgmtPushRecordService;
import com.pig4cloud.pig.marketing.service.TcpDataService;
import com.pig4cloud.pig.statistics.api.entity.user.MktStatActiveUser;
import com.pig4cloud.pig.statistics.api.entity.user.MktStatNewUser;
import com.pig4cloud.pig.statistics.api.feign.RemoteStatUserDataService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: lwh
 * @date: 2025-08-28
 * @description: TCP数据服务实现类
 */

	@Slf4j
	@Service
	@AllArgsConstructor
	public class TcpDataServiceImpl implements TcpDataService {

		private final MongoTemplate mongoTemplate;

		private final MessageRepository messageRepository;

		private final UserStatisticsConfig userStatisticsConfig;

		@Autowired
		private MktMgmtPushRecordService mktMgmtPushRecordService;

		@Autowired
		private MktMgmtHandPushService mktMgmtHandPushService;

		private final RemoteStatUserDataService remoteStatUserDataService;

		// JSON处理器
		private final ObjectMapper objectMapper = new ObjectMapper();

	// 定义时间格式器
	private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

	/**
	 * 保存或更新设备信息
	 * @param reqDto
	 * @return
	 */
	@Override
	public String saveOrUpdateDevice(SaveDeviceInfoDTO reqDto) {
		if (reqDto.getClientIp() != null) {
			reqDto.setClientIp(reqDto.getClientIp().split(":")[0]);
		}

		// 根据客户端ID查询设备信息
		Query query = new Query(Criteria.where("clientID").is(reqDto.getClientID()));
		Device existingDevice = mongoTemplate.findOne(query, Device.class);

		if (existingDevice == null) {
			// 无数据时直接新增
			Device device = new Device();
			device.setClientID(reqDto.getClientID());
			device.setDeviceInfo(reqDto.getDeviceInfo());
			device.setHeadInfo(reqDto.getHeadInfo());
			device.setClientIp(reqDto.getClientIp());
			// 设置创建时间和更新时间为当前时间的字符串格式
			String currentTime = LocalDateTime.now().format(DATE_TIME_FORMATTER);
			device.setCreateTime(currentTime);
			device.setUpdateTime(currentTime);
			Device insert = mongoTemplate.insert(device);

			// 生成新增用户数据并同步
			syncNewUserData(device);
			// 生成一条活跃数据并同步
			syncActiveUserData(device);

			return insert.getId();
		} else {
			// 有数据时对比设备信息是否一致
			if (!Objects.equals(existingDevice.getDeviceInfo(), reqDto.getDeviceInfo())
					|| !Objects.equals(existingDevice.getHeadInfo(), reqDto.getHeadInfo())) {
				// 信息不一致则更新
				Update update = new Update();
				if (!StringUtils.isBlank(reqDto.getDeviceInfo())) {
					update.set("deviceInfo", reqDto.getDeviceInfo());

					syncNewUserData(existingDevice, reqDto.getDeviceInfo());
					synActiveUserData(existingDevice, reqDto.getDeviceInfo());
				}
				if (!StringUtils.isBlank(reqDto.getHeadInfo())) {
					update.set("headInfo", reqDto.getHeadInfo());
				}
				// 设置更新时间为当前时间的字符串格式
				update.set("updateTime", LocalDateTime.now().format(DATE_TIME_FORMATTER));

				update.set("clientIp", reqDto.getClientIp());

				mongoTemplate.updateFirst(query, update, Device.class);

				return existingDevice.getId();
			}
		}
		return existingDevice.getId();
	}

	private void synActiveUserData(Device device, String deviceInfo) {
		if(device ==null) {
			return;
		}
		String clientID = device.getClientID();

		// 将deviceInfo从JSON字符串转换为JSON对象
		JsonNode deviceInfoJson = null;
		try {
			if (deviceInfo != null && !deviceInfo.trim().isEmpty()) {
				String subDeviceInfo = deviceInfo.trim().substring(deviceInfo.indexOf("{"));
				deviceInfoJson = objectMapper.readTree(subDeviceInfo);
			}
		} catch (Exception e) {
			log.error("syncActiveUserData fail = {}", e.getMessage());
			return;
		}

		// 从JSON对象中提取需要的字段
		String bundle = extractStringFromJson(deviceInfoJson, "bundle", "");
		String appId = extractStringFromJson(deviceInfoJson, "appId", bundle);
		String channel = extractStringFromJson(deviceInfoJson, "channel", "应用市场");
		String version = extractStringFromJson(deviceInfoJson, "version", "0.0.0");

		// 同步新增用户数据 -> mysql
		// 构建mkt_stat_new_user对象
		MktStatActiveUser activeUser = new MktStatActiveUser();
		activeUser.setUserId(clientID);
		activeUser.setAppId(appId);
		activeUser.setChannel(channel);
		activeUser.setVersion(version);
		activeUser.setStatDate(LocalDateTime.now());

		R<Boolean> result = remoteStatUserDataService.updateMktStatActiveUser(activeUser);
		if (result.getData() == null || !result.getData()) {
			log.error("update活跃用户记录失败：clientID = {}", clientID);
		} else {
			log.debug("update活跃用户记录成功：clientID = {}, appId = {}, channel = {}", clientID, appId, channel);
		}
	}

	private void syncNewUserData(Device device, String deviceInfo) {
		if (device ==null) {
			return;
		}

		String clientID = device.getClientID();

		// 将deviceInfo从JSON字符串转换为JSON对象
		JsonNode deviceInfoJson = null;
		try {
			if (deviceInfo != null && !deviceInfo.trim().isEmpty()) {
				String subDeviceInfo = deviceInfo.trim().substring(deviceInfo.indexOf("{"));
				deviceInfoJson = objectMapper.readTree(subDeviceInfo);
			}
		} catch (Exception e) {
			log.error("syncActiveUserData fail = {}", e.getMessage());
			return;
		}

		// 从JSON对象中提取需要的字段
		String bundle = extractStringFromJson(deviceInfoJson, "bundle", "");
		String appId = extractStringFromJson(deviceInfoJson, "appId", bundle);
		String channel = extractStringFromJson(deviceInfoJson, "channel", "应用市场");
		String version = extractStringFromJson(deviceInfoJson, "version", "0.0.0");
		String oldVersion = extractStringFromJson(deviceInfoJson, "oldVersion", "");

		// 同步新增用户数据 -> mysql
		// 构建mkt_stat_new_user对象
		MktStatNewUser mktStatNewUser = new MktStatNewUser();
		mktStatNewUser.setUserId(clientID);
		mktStatNewUser.setAppId(appId);
		mktStatNewUser.setChannel(channel);
		mktStatNewUser.setVersion(version);
		mktStatNewUser.setOldVersion(oldVersion);
		mktStatNewUser.setStatDate(LocalDateTime.now());

		R<Boolean> result = remoteStatUserDataService.updateMktStatNewUser(mktStatNewUser);
		if (result.getData() == null || !result.getData()) {
			log.error("update新增用户记录失败：clientID = {}", clientID);
		} else {
			log.debug("update新增用户记录成功：clientID = {}, appId = {}, channel = {}", clientID, appId, channel);
		}
	}

	private void syncActiveUserData(Device device) {
		if (device ==null) {
			return;
		}
		String clientID = device.getClientID();
		// 通过clientID查询设备详情
		String deviceInfo = device.getDeviceInfo();

		// 将deviceInfo从JSON字符串转换为JSON对象
		JsonNode deviceInfoJson = null;
		try {
			if (deviceInfo != null && !deviceInfo.trim().isEmpty()) {
				String subDeviceInfo = deviceInfo.trim().substring(deviceInfo.indexOf("{"));
				deviceInfoJson = objectMapper.readTree(subDeviceInfo);
			}
		} catch (Exception e) {
			log.error("syncActiveUserData fail = {}", e.getMessage());
			return;
		}

		// 从JSON对象中提取需要的字段
		String bundle = extractStringFromJson(deviceInfoJson, "bundle", "");
		String appId = extractStringFromJson(deviceInfoJson, "appId", bundle);
		String channel = extractStringFromJson(deviceInfoJson, "channel", "应用市场");
		String version = extractStringFromJson(deviceInfoJson, "version", "0.0.0");

		// 同步新增用户数据 -> mysql
		// 构建mkt_stat_new_user对象
		MktStatActiveUser activeUser = new MktStatActiveUser();
		activeUser.setUserId(clientID);
		activeUser.setAppId(appId);
		activeUser.setChannel(channel);
		activeUser.setVersion(version);
		activeUser.setStatDate(LocalDateTime.now());

		R<Boolean> result = remoteStatUserDataService.saveMktStatActiveUser(activeUser);
		if (result.getData() == null || !result.getData()) {
			log.error("add活跃用户记录失败：clientID = {}", clientID);
		} else {
			log.debug("add活跃用户记录成功：clientID = {}, appId = {}, channel = {}", clientID, appId, channel);
		}
	}

	/**
	 * 同步新增用户数据
	 * @param device 设备信息
	 */
	private void syncNewUserData(Device device) {
		String clientID = device.getClientID();
		// 通过clientID查询设备详情
		String deviceInfo = device.getDeviceInfo();
		// 将deviceInfo从JSON字符串转换为JSON对象
		JsonNode deviceInfoJson = null;
		try {
			if (deviceInfo != null && !deviceInfo.trim().isEmpty()) {
				String subDeviceInfo = deviceInfo.trim().substring(deviceInfo.indexOf("{"));
				deviceInfoJson = objectMapper.readTree(subDeviceInfo);
			}
		} catch (Exception e) {
			log.error("syncNewUserData fail = {}", e.getMessage());
		}

		// 从JSON对象中提取需要的字段
		String bundle = extractStringFromJson(deviceInfoJson, "bundle", "");
		String appId = extractStringFromJson(deviceInfoJson, "appId", bundle);
		String channel = extractStringFromJson(deviceInfoJson, "channel", "应用市场");
		String version = extractStringFromJson(deviceInfoJson, "version", "0.0.0");
		String oldVersion = extractStringFromJson(deviceInfoJson, "oldVersion", "");

		// 同步新增用户数据 -> mysql
		// 构建mkt_stat_new_user对象
		MktStatNewUser mktStatNewUser = new MktStatNewUser();
		mktStatNewUser.setUserId(clientID);
		mktStatNewUser.setAppId(appId);
		mktStatNewUser.setChannel(channel);
		mktStatNewUser.setVersion(version);
		mktStatNewUser.setOldVersion(oldVersion);
		mktStatNewUser.setStatDate(LocalDateTime.now());

		R<Boolean> result = remoteStatUserDataService.saveMktStatNewUser(mktStatNewUser);
		if (result.getData() == null || !result.getData()) {
			log.error("add新增用户记录失败：clientID = {}", clientID);
		} else {
			log.debug("add新增用户记录成功：clientID = {}, appId = {}, channel = {}", clientID, appId, channel);
		}
	}

	/**
	 * 从JSON对象中提取字符串字段
	 * @param jsonNode JSON节点
	 * @param fieldName 字段名
	 * @param defaultValue 默认值
	 * @return 提取的字符串值
	 */
	private String extractStringFromJson(JsonNode jsonNode, String fieldName, String defaultValue) {
		try {
			if (jsonNode != null && jsonNode.has(fieldName)) {
				JsonNode fieldNode = jsonNode.get(fieldName);
				if (fieldNode != null && !fieldNode.isNull()) {
					return fieldNode.asText();
				}
			}
		} catch (Exception e) {
			log.warn("提取JSON字段失败：fieldName = {}, 错误：{}", fieldName, e.getMessage());
		}
		return defaultValue;
	}

	/**
	 * 根据客户端ID查询设备信息
	 * @param clientID 客户端ID
	 * @return 设备信息
	 */
	@Override
	public Device getDeviceByClientID(String clientID) {
		return mongoTemplate.findOne(
				new Query(Criteria.where("clientID").is(clientID)),
				Device.class
		);
	}

	/**
	 * 分页查询设备信息
	 * @param reqDto 入参
	 * @return 设备信息列表
	 */
	@Override
	public Page<PageDeviceInfoVO> pageDeviceInfo(PageDeviceInfoDTO reqDto) {
		// 创建查询条件
		Criteria criteria = new Criteria();

		// 添加clientID条件
		if (reqDto.getClientID() != null && !reqDto.getClientID().trim().isEmpty()) {
			criteria.and("clientID").regex(reqDto.getClientID());
		}

		// 添加时间范围条件
		LocalDateTime startTime = reqDto.getStartTime();
		LocalDateTime endTime = reqDto.getEndTime();

		// 创建时间字段的条件对象
		Criteria timeCriteria = new Criteria("createTime");

		if (startTime != null) {
			String startStr = startTime.format(DATE_TIME_FORMATTER);
			timeCriteria.gte(startStr);
		}

		if (endTime != null) {
			String endStr = endTime.format(DATE_TIME_FORMATTER);
			timeCriteria.lte(endStr);
		}

		// 只有当存在时间条件时，才将时间条件添加到主条件中
		if (startTime != null || endTime != null) {
			criteria.andOperator(timeCriteria);
		}

		// 创建查询对象
		Query query = new Query(criteria);

		// 计算总记录数
		long total = mongoTemplate.count(query, Device.class);

		// 设置分页和排序
		Pageable pageable = PageRequest.of(
				reqDto.getCurrent() - 1,  // MongoDB页码从0开始
				reqDto.getSize(),
				Sort.by(Sort.Direction.DESC, "createTime")
		);
		query.with(pageable);

		// 执行查询
		List<Device> devices = mongoTemplate.find(query, Device.class);

		List<PageDeviceInfoVO> result = new ArrayList<>();
		// 组装数据
		for (Device device : devices) {
			PageDeviceInfoVO info = new PageDeviceInfoVO();
			BeanUtils.copyProperties(device, info);

			// 查询总条数
			Long dataTotal = getMsgDataTotal(device.getClientID());
			info.setTotal(dataTotal);

			// 查询最新推送时间
			String latestPushTime = getLatestPushTime(device.getClientID());
			info.setLatestPushTime(latestPushTime);

			result.add(info);
		}

		// 封装分页结果
		Page<PageDeviceInfoVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize(), total);
		page.setRecords(result);
		return page;
	}

	/******************************************* 消息 *******************************************
	 * 保存上报数据
	 * @param reqDto 入参
	 * @return 数据ID
	 */
	@Override
	public String saveMessage(SaveTcpMessageDTO reqDto) {
		if (reqDto.getClientIp() != null) {
			reqDto.setClientIp(reqDto.getClientIp().split(":")[0]);
		}

		Message message = new Message();
		message.setClientID(reqDto.getClientID());
		message.setMsgData(reqDto.getMsgData());
		message.setClientIp(reqDto.getClientIp());
		message.setReportTime(LocalDateTime.now().format(DATE_TIME_FORMATTER));
		Message save = messageRepository.save(message);
		MktMgmtPushRecordSaveDTO saveRecordDTO = new MktMgmtPushRecordSaveDTO();
		String s = "";
		String hand = "";
		if (save.getId() != null) {
			saveRecordDTO.setPushContent(reqDto.getMsgData());
			saveRecordDTO.setPushIP(reqDto.getClientIp());
			saveRecordDTO.setPushDomain(reqDto.getClientDomain());
			saveRecordDTO.setClientId(reqDto.getClientID());

			s = mktMgmtPushRecordService.saveRecord(saveRecordDTO);
			hand = mktMgmtHandPushService.handPush(saveRecordDTO);

			// 根据客户端ID查询设备信息
			Query query = new Query(Criteria.where("clientID").is(reqDto.getClientID()));
			Device device = mongoTemplate.findOne(query, Device.class);
			syncActiveUserData(device);
		}

		log.info("保存推送记录：{}--{}", s,hand);
		return save.getId();
	}

	/**
	 * 根据ID查询数据详情
	 * @param id 数据ID
	 * @return 数据详情
	 */
	@Override
	public Message getMessagesById(String id) {
		return messageRepository.findById(id)
				.orElse(null);
	}

	/**
	 * 分页查询数据列表
	 * @param reqDto 入参
	 * @return 数据列表
	 */
	@Override
	public Page<Message> pageMsgInfo(PageMessageDTO reqDto) {
		// 创建查询条件
		Criteria criteria = new Criteria();

		// 添加clientID条件
		criteria.and("clientID").is(reqDto.getClientID());

		if (reqDto.getKeyWord() != null && !reqDto.getKeyWord().isEmpty()){
			criteria.and("msgData").regex(reqDto.getKeyWord());
		}

		// 添加时间范围条件
		LocalDateTime startTime = reqDto.getStartTime();
		LocalDateTime endTime = reqDto.getEndTime();

		// 创建时间字段的条件对象
		Criteria timeCriteria = new Criteria("reportTime");

		if (startTime != null) {
			String startStr = startTime.format(DATE_TIME_FORMATTER);
			timeCriteria.gte(startStr);
		}

		if (endTime != null) {
			String endStr = endTime.format(DATE_TIME_FORMATTER);
			timeCriteria.lte(endStr);
		}

		// 只有当存在时间条件时，才将时间条件添加到主条件中
		if (startTime != null || endTime != null) {
			criteria.andOperator(timeCriteria);
		}

		// 创建查询对象
		Query query = new Query(criteria);

		// 计算总记录数
		long total = mongoTemplate.count(query, Message.class);

		// 设置分页和排序
		Pageable pageable = PageRequest.of(
				reqDto.getCurrent() - 1,  // MongoDB页码从0开始
				reqDto.getSize(),
				Sort.by(Sort.Direction.DESC, "reportTime")
		);
		query.with(pageable);

		// 执行查询
		List<Message> messages = mongoTemplate.find(query, Message.class);

		// 封装分页结果
		Page<Message> page = new Page<>(reqDto.getCurrent(), reqDto.getSize(), total);
		page.setRecords(messages);
		return page;
	}


	/**
	 * 获取设备总数据条数
	 * @param clientId 客户端ID
	 * @return 设备总数据条数
	 */
	private Long getMsgDataTotal(String clientId){
		// 创建查询条件
		Criteria criteria = new Criteria();

		// 添加clientID条件
		criteria.and("clientID").is(clientId);

		// 创建查询对象
		Query query = new Query(criteria);

		// 计算总记录数
		return mongoTemplate.count(query, Message.class);

	}

	/**
	 * 获取指定客户端的最新推送时间
	 * @param clientId 客户端ID
	 * @return 最新推送时间，如果没有数据则返回null
	 */
	private String getLatestPushTime(String clientId) {
		// 创建查询条件
		Criteria criteria = Criteria.where("clientID").is(clientId);
		Query query = new Query(criteria);

		// 按reportTime降序排序，只取第一条记录
		query.with(Sort.by(Sort.Direction.DESC, "reportTime")).limit(1);

		// 执行查询
		Message latestMessage = mongoTemplate.findOne(query, Message.class);

		// 返回最新推送时间，如果没有数据则返回null
		return latestMessage != null ? latestMessage.getReportTime() : null;
	}

	/**
	 * 统计用户数
	 * @return 用户统计信息
	 */
	@Override
	public UserStatisticsVO getUserStatistics() {
		log.info("开始统计用户数");
		
		try {
			// 1. 统计累计用户数
			Long totalUsers = getTotalUsers();
			
			// 2. 统计活跃用户数
			Long activeUsers = getActiveUsers();
			
			// 3. 构建返回结果
			UserStatisticsVO statisticsVO = new UserStatisticsVO();
			statisticsVO.setTotalUsers(totalUsers);
			statisticsVO.setActiveUsers(activeUsers);
			statisticsVO.setStatisticsTime(LocalDateTime.now().format(DATE_TIME_FORMATTER));
			statisticsVO.setActiveTimeRange(userStatisticsConfig.getActiveTimeRangeMinutes());
			
			log.info("用户统计完成，累计用户数：{}，活跃用户数：{}", totalUsers, activeUsers);
			return statisticsVO;
			
		} catch (Exception e) {
			log.error("统计用户数异常", e);
			// 返回默认值
			UserStatisticsVO statisticsVO = new UserStatisticsVO();
			statisticsVO.setTotalUsers(0L);
			statisticsVO.setActiveUsers(0L);
			statisticsVO.setStatisticsTime(LocalDateTime.now().format(DATE_TIME_FORMATTER));
			statisticsVO.setActiveTimeRange(userStatisticsConfig.getActiveTimeRangeMinutes());
			return statisticsVO;
		}
	}
	
	/**
	 * 获取累计用户数
	 * @return 累计用户数
	 */
	private Long getTotalUsers() {
		// 使用MongoDB的distinct操作获取去重的clientID数量
		List<String> distinctClientIDs = mongoTemplate.findDistinct(
			new Query(), 
			"clientID", 
			Device.class, 
			String.class
		);
		
		// 过滤掉null和空字符串
		long count = distinctClientIDs.stream()
			.filter(clientID -> clientID != null && !clientID.trim().isEmpty())
			.count();
			
		log.debug("累计用户数统计完成，去重后的clientID数量：{}", count);
		return count;
	}
	
	/**
	 * 获取活跃用户数
	 * @return 活跃用户数
	 */
	private Long getActiveUsers() {
		// 计算活跃时间范围
		LocalDateTime activeStartTime = LocalDateTime.now().minusMinutes(userStatisticsConfig.getActiveTimeRangeMinutes());
		String activeStartTimeStr = activeStartTime.format(DATE_TIME_FORMATTER);
		
		// 创建查询条件：时间在活跃时间范围内
		Criteria criteria = Criteria.where("reportTime").gte(activeStartTimeStr);
		Query query = new Query(criteria);
		
		// 使用distinct操作获取去重的clientID数量
		List<String> distinctClientIDs = mongoTemplate.findDistinct(
			query, 
			"clientID", 
			Message.class, 
			String.class
		);
		
		// 过滤掉null和空字符串
		long count = distinctClientIDs.stream()
			.filter(clientID -> clientID != null && !clientID.trim().isEmpty())
			.count();
			
		log.debug("活跃用户数统计完成，时间范围：{} 至现在，去重后的clientID数量：{}", activeStartTimeStr, count);
		return count;
	}

	/**
	 * 查询在线用户列表
	 * @return 在线用户列表
	 */
	@Override
	public List<OnlineUserVO> getOnlineUsers() {
		log.info("开始查询在线用户列表");
		
		try {
			// 计算最近10分钟的时间范围
			LocalDateTime tenMinutesAgo = LocalDateTime.now().minusMinutes(userStatisticsConfig.getActiveTimeRangeMinutes());
			String tenMinutesAgoStr = tenMinutesAgo.format(DATE_TIME_FORMATTER);
			
			// 创建查询条件：时间在最近10分钟内
			Criteria criteria = Criteria.where("reportTime").gte(tenMinutesAgoStr);
			Query query = new Query(criteria);
			
			// 获取所有符合条件的消息
			List<Message> messages = mongoTemplate.find(query, Message.class);
			
			// 按clientID分组，获取每个clientID的最新消息
			Map<String, Message> latestMessagesByClient = messages.stream()
				.filter(msg -> msg.getClientID() != null && !msg.getClientID().trim().isEmpty())
				.collect(Collectors.groupingBy(
					Message::getClientID,
					Collectors.collectingAndThen(
						Collectors.maxBy(Comparator.comparing(Message::getReportTime)),
						opt -> opt.orElse(null)
					)
				));
			
			// 转换为OnlineUserVO列表
			List<OnlineUserVO> onlineUsers = latestMessagesByClient.values().stream()
				.filter(Objects::nonNull)
				.map(this::convertToOnlineUserVO)
				.sorted(Comparator.comparing(OnlineUserVO::getLastActiveTime).reversed())
				.collect(Collectors.toList());
			
			log.info("在线用户列表查询完成，共找到 {} 个在线用户", onlineUsers.size());
			// 只返回前十条记录
			int limit = Math.min(onlineUsers.size(), 10);
			return onlineUsers.subList(0, limit);
			
		} catch (Exception e) {
			log.error("查询在线用户列表异常", e);
			return new ArrayList<>();
		}
	}
	
	/**
	 * 将Message转换为OnlineUserVO
	 * @param message 消息对象
	 * @return 在线用户VO
	 */
	private OnlineUserVO convertToOnlineUserVO(Message message) {
		OnlineUserVO onlineUserVO = new OnlineUserVO();
		onlineUserVO.setClientID(message.getClientID());

		// 设置最后活跃时间
		if (message.getReportTime() != null) {
			try {
				LocalDateTime reportDateTime = LocalDateTime.parse(message.getReportTime(), DATE_TIME_FORMATTER);
				onlineUserVO.setLastActiveTime(reportDateTime);
			} catch (Exception e) {
				log.warn("解析时间失败，clientID: {}, reportTime: {}", message.getClientID(), message.getReportTime());
				onlineUserVO.setLastActiveTime(LocalDateTime.now());
			}
		} else {
			onlineUserVO.setLastActiveTime(LocalDateTime.now());
		}
		
		return onlineUserVO;
	}

	/**
	 * 用户地区统计
	 * @param reqDto 查询条件
	 * @return 用户地区统计信息
	 */
	@Override
	public UserRegionStatisticsVO getUserRegionStatistics(UserRegionStatisticsDTO reqDto) {
		log.info("开始统计用户地区分布，查询条件：{}", reqDto);
		
		try {
			// 1. 构建时间范围
			LocalDateTime endTime = LocalDateTime.now();
			LocalDateTime startTime = endTime.minusDays(reqDto.getDays());
			
			// 2. 根据查询类型构建不同的查询条件
			Query query = buildQueryByType(reqDto.getQueryType(), startTime, endTime);
			
			// 3. 查询设备数据
			List<Device> devices = mongoTemplate.find(query, Device.class);
			
			// 4. 按IP解析国家并统计
			Map<String, Long> countryCountMap = new HashMap<>();
			
			for (Device device : devices) {
				if (StringUtils.isNotBlank(device.getClientIp())) {
					log.debug("正在解析IP：{}", device.getClientIp());
					String country = getCountryFromIp(device.getClientIp());
					if (StringUtils.isNotBlank(country) && !"未知".equals(country) && !"内网".equals(country)) {
						countryCountMap.merge(country, 1L, Long::sum);
					}
				}
			}
			
			// 5. 构建返回结果
			UserRegionStatisticsVO result = new UserRegionStatisticsVO();
			result.setStatisticsTime(LocalDateTime.now().format(DATE_TIME_FORMATTER));
			result.setDays(reqDto.getDays());
			result.setQueryType(reqDto.getQueryType());
			
			List<RegionStatisticsItem> countryStatistics = new ArrayList<>();
			long totalUsers = countryCountMap.values().stream().mapToLong(Long::longValue).sum();
			
			// 按用户数量降序排列
			countryCountMap.entrySet().stream()
				.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
				.forEach(entry -> {
					RegionStatisticsItem item = new RegionStatisticsItem();
					item.setCountry(entry.getKey());
					item.setUserCount(entry.getValue());
					countryStatistics.add(item);
				});
			
			result.setCountryStatistics(countryStatistics);
			result.setTotalUsers(totalUsers);
			
			log.info("用户地区统计完成，总用户数：{}，国家数量：{}", totalUsers, countryStatistics.size());
			return result;
			
		} catch (Exception e) {
			log.error("统计用户地区分布异常", e);
			// 返回默认值
			UserRegionStatisticsVO result = new UserRegionStatisticsVO();
			result.setStatisticsTime(LocalDateTime.now().format(DATE_TIME_FORMATTER));
			result.setDays(reqDto.getDays());
			result.setQueryType(reqDto.getQueryType());
			result.setCountryStatistics(new ArrayList<>());
			result.setTotalUsers(0L);
			return result;
		}
	}
	
	/**
	 * 根据查询类型构建查询条件
	 * @param queryType 查询类型
	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 * @return 查询条件
	 */
	private Query buildQueryByType(String queryType, LocalDateTime startTime, LocalDateTime endTime) {
		Query query = new Query();
		
		switch (queryType.toLowerCase()) {
			case "visitor":
				// 访客数：统计指定时间范围内有设备记录的用户
				query.addCriteria(Criteria.where("createTime").gte(startTime.format(DATE_TIME_FORMATTER))
										  .lte(endTime.format(DATE_TIME_FORMATTER)));
				break;
			case "active":
				// 活跃用户数：统计指定时间范围内有消息记录的用户
				// 这里需要查询Message表，然后通过clientID关联Device表
				Query messageQuery = new Query();
				messageQuery.addCriteria(Criteria.where("reportTime").gte(startTime.format(DATE_TIME_FORMATTER))
												  .lte(endTime.format(DATE_TIME_FORMATTER)));
				
				List<String> activeClientIDs = mongoTemplate.findDistinct(
					messageQuery, 
					"clientID", 
					Message.class, 
					String.class
				);
				
				// 过滤掉null和空字符串
				List<String> validClientIDs = activeClientIDs.stream()
					.filter(clientID -> clientID != null && !clientID.trim().isEmpty())
					.collect(Collectors.toList());
				
				if (!validClientIDs.isEmpty()) {
					query.addCriteria(Criteria.where("clientID").in(validClientIDs));
				} else {
					// 如果没有活跃用户，返回空结果
					query.addCriteria(Criteria.where("clientID").in(Collections.emptyList()));
				}
				break;
			case "total":
				// 总用户数：统计所有用户（不限制时间）
				// 不需要添加时间条件
				break;
			default:
				log.warn("未知的查询类型：{}，使用默认的visitor类型", queryType);
				query.addCriteria(Criteria.where("createTime").gte(startTime.format(DATE_TIME_FORMATTER))
										  .lte(endTime.format(DATE_TIME_FORMATTER)));
				break;
		}
		
		return query;
	}
	
	/**
	 * 从IP地址获取国家信息
	 * @param ip IP地址
	 * @return 国家名称
	 */
	private String getCountryFromIp(String ip) {
		try {
			String region = IPUtils.getIpRegion(ip);
			if (StringUtils.isNotBlank(region) && !"未知".equals(region) && !"内网".equals(region)) {
				// 解析地区信息，格式通常是"国家-省份"
				String[] parts = region.split("-");
				if (parts.length >= 1) {
					return parts[0].trim();
				}
			}
		} catch (Exception e) {
			log.warn("解析IP[{}]归属地失败", ip, e);
		}
		return "未知";
	}
}
