package com.centreproject.system.service.guestExperience.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.centreproject.common.constant.GuestConstants;
import com.centreproject.common.constant.KeyConstants;
import com.centreproject.common.utils.DateUtils;
import com.centreproject.common.websocket.MyWebSocketHandler;
import com.centreproject.system.domain.kpi.guestExperience.KpiVisitorCountryBreakdown;
import com.centreproject.system.domain.kpi.park.ParkAgeGroupStatistics;
import com.centreproject.system.domain.kpi.park.ParkTicketType;
import com.centreproject.system.domain.vo.KpiVisitorCountryBreakdownVo;
import com.centreproject.system.mapper.kpi.KpiVisitorCountryBreakdownMapper;
import com.centreproject.system.mapper.park.ParkAgeGroupStatisticsMapper;
import com.centreproject.system.service.guestExperience.IKpiVisitorCountryBreakdownService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author zhonglei.xu
 * @description 国籍统计相关接口
 */
@Service
public class KpiVisitorCountryBreakdownServiceImpl extends ServiceImpl<KpiVisitorCountryBreakdownMapper, KpiVisitorCountryBreakdown>
        implements IKpiVisitorCountryBreakdownService {
    private Logger logger = LoggerFactory.getLogger(KpiVisitorCountryBreakdownServiceImpl.class);
    @Autowired
    private KpiVisitorCountryBreakdownMapper mapper;

    @Autowired
    private RedisTemplate<String, List<KpiVisitorCountryBreakdown>> redisTemplate;


    @Autowired
    private RedisTemplate<Object, Object> redisTemplateObject;
    // WebSocket消息发送器
    @Autowired
    private MyWebSocketHandler myWebSocketHandler;

    @Autowired
    private ParkAgeGroupStatisticsMapper parkAgeGroupStatisticsMapper;

    /**
     * 近60天访客国籍分析
     * Visitor_Breakdown_By_Country_Of_Residence last 60 days
     * @return
     */
    @Override
    public List<KpiVisitorCountryBreakdown> getVisitorBreakdownByCountryOfResidence() {
        String redisKey = KeyConstants.VISITOR_BREAKDOWN_BY_COUNTRY_OF_RESIDENCE + DateUtils.getRiDate() + GuestConstants.LATEST_60_DAYS;

        // 1. 查缓存
        List<KpiVisitorCountryBreakdown> cached = redisTemplate.opsForValue().get(redisKey);
        if (CollectionUtils.isNotEmpty(cached)) {
            return cached;
        }

        // 2. 根据类型处理数据
        List<KpiVisitorCountryBreakdown> results = mapper.getVisitorBreakdownByCountryOfResidenceLatest60Days();


        // 3. 写缓存（仅60天数据需要缓存）
        if (CollectionUtils.isNotEmpty(results)) {
            redisTemplate.opsForValue().set(redisKey, results, 1, TimeUnit.HOURS);
        }

        return results;
    }

    /**
     * 根据园区编码对访客国籍分析
     * Visitor_Breakdown_By_Country_Of_Residence last 60 days by park_code
     * @param parkCode
     * @return
     */
    @Override
    public KpiVisitorCountryBreakdownVo getVisitorBreakdownByCountryOfResidenceByParkCode(String parkCode) {
        String redisKey = KeyConstants.VISITOR_BREAKDOWN_BY_COUNTRY_OF_RESIDENCE +parkCode+ DateUtils.getRiDate() + GuestConstants.LATEST_60_DAYS;

        // 1. 查缓存
        KpiVisitorCountryBreakdownVo cached = (KpiVisitorCountryBreakdownVo)redisTemplateObject.opsForValue().get(redisKey);
        if (ObjectUtils.isNotEmpty(cached)) {
            return cached;
        }

        // 2. 根据类型处理数据
        // 国籍分布
        List<KpiVisitorCountryBreakdown> results = mapper.getVisitorBreakdownByCountryOfResidenceLatest60DaysByParkCode(parkCode);
        KpiVisitorCountryBreakdownVo vo = new KpiVisitorCountryBreakdownVo();
        if (CollectionUtils.isNotEmpty(results)) {
            vo.setVisitorCountryBreakdown(results);
        }
        // 男女分布
        KpiVisitorCountryBreakdown gender = mapper.getGenderDistribution(parkCode);
        if(ObjectUtils.isNotEmpty(gender)){
            vo.setWomen(gender.getWomen());
            vo.setMan(gender.getMan());
        }
        // 年龄分布
        LocalDate today = DateUtils.getNowLocalDate();

        LambdaQueryWrapper<ParkAgeGroupStatistics> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ParkAgeGroupStatistics::getStatisticsDate, today);
        wrapper.eq(ParkAgeGroupStatistics::getParkCode, parkCode);
        wrapper.orderByAsc(ParkAgeGroupStatistics::getAgeGroup);
        List<ParkAgeGroupStatistics> parkAgeGroupStatistics = parkAgeGroupStatisticsMapper.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(parkAgeGroupStatistics)) {
            vo.setByAgeGroup(parkAgeGroupStatistics);
        }
        if(ObjectUtils.isNotEmpty(vo)) {
            redisTemplateObject.opsForValue().set(redisKey, vo, 10, TimeUnit.MINUTES);
        }
        return vo;
    }




    /******************************  定时模拟数据推送  *********************************/


    /**
     * 模拟定时任务往websocket发送消息
     * Visitor_Breakdown_By_Country_Of_Residence daily
     */
    @Scheduled(fixedRate = 30000) // 每30秒执行一次
    public void visitorBreakdownByCountryOfResidenceDailyDays() {
        try {
            // 1. 从数仓获取最新数据（示例）
            //    取当天的数据，再分组推送
            List<KpiVisitorCountryBreakdown> latestData = mapper.getVisitorBreakdownByCountryOfResidenceDailyDays();
            if (CollectionUtils.isNotEmpty(latestData)) {

                // 构建每个园区的独立消息
                Map<String, Object> message = new HashMap<>();
                message.put("module", KeyConstants.VISITOR_BREAKDOWN_BY_COUNTRY_OF_RESIDENCE);
                message.put("data", latestData);
                message.put("timestamp", System.currentTimeMillis());
                // 转换为JSON并推送
                String jsonData = JSON.toJSONString(message);
                myWebSocketHandler.broadcast(jsonData);
                logger.info("模块{}数据推送成功，项目数量: {}", KeyConstants.VISITOR_BREAKDOWN_BY_COUNTRY_OF_RESIDENCE, latestData.size());

            }

        } catch (Exception e) {
            logger.error("数据获取或推送异常", e);
        }
    }

    /**
     * 模拟定时任务往websocket发送消息
     * Visitor_Breakdown_By_Country_Of_Residence daily group by parkCode push websocket
     */
    @Scheduled(fixedRate = 30000) // 每30秒执行一次
    public void visitorBreakdownByCountryOfResidenceDailyDaysByParkCode() {
        try {
            // 1. 从数仓获取最新数据（示例）
            //    取当天的数据，再分组推送
            List<KpiVisitorCountryBreakdown> latestData = mapper.getVisitorBreakdownByCountryOfResidenceDailyDaysByParkCode();
            if (CollectionUtils.isNotEmpty(latestData)) {
                // 2. 按园区(park_code)分组并排序
                Map<String, List<KpiVisitorCountryBreakdown>> groupedData = latestData.stream()
                        .collect(Collectors.groupingBy(
                                KpiVisitorCountryBreakdown::getParkCode,
                                Collectors.collectingAndThen(
                                        Collectors.toList(),
                                        list -> list.stream()
                                                .sorted(Comparator.comparing(KpiVisitorCountryBreakdown::getVisitorCount).reversed())
                                                .collect(Collectors.toList())
                                )
                        ));
                // 年龄分布
                LocalDate today = DateUtils.getNowLocalDate();
                LambdaQueryWrapper<ParkAgeGroupStatistics> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(ParkAgeGroupStatistics::getStatisticsDate, today);
                wrapper.orderByAsc(ParkAgeGroupStatistics::getAgeGroup);
                List<ParkAgeGroupStatistics> parkAgeGroupStatistics = parkAgeGroupStatisticsMapper.selectList(wrapper);
                Map<String, List<ParkAgeGroupStatistics>> map = parkAgeGroupStatistics.stream().collect(Collectors.groupingBy(ParkAgeGroupStatistics::getParkCode));
                // 3. 按园区分组推送
                groupedData.forEach((parkCode, parkData) -> {
                    KpiVisitorCountryBreakdownVo vo = new KpiVisitorCountryBreakdownVo();
                    vo.setVisitorCountryBreakdown(parkData);
                    // 女生合计
                    int women = parkData.stream()
                           .mapToInt(KpiVisitorCountryBreakdown::getWomen)
                           .sum();

                    int man = parkData.stream()
                            .mapToInt(KpiVisitorCountryBreakdown::getMan)
                            .sum();
                    vo.setWomen(women);
                    vo.setMan(man);
                    vo.setByAgeGroup(map.get(parkCode));
                    // 构建每个园区的独立消息
                    Map<String, Object> message = new HashMap<>();
                    message.put("module", KeyConstants.PARK_VISITOR_ORIGIN_BREAKDOWN_BY_COUNTRY + parkCode);
                    message.put("data", vo);
                    message.put("timestamp", System.currentTimeMillis());
                    // 转换为JSON并推送
                    String jsonData = JSON.toJSONString(message);
                    myWebSocketHandler.broadcast(jsonData);
                    logger.info("模块{}园区[{}]数据推送成功，项目数量: {}", KeyConstants.PARK_VISITOR_ORIGIN_BREAKDOWN_BY_COUNTRY, parkCode, parkData.size());
                });
            }

        } catch (Exception e) {
            logger.error("数据获取或推送异常", e);
        }
    }


}
