package com.ycwl.basic.service.pc.impl;

import com.ycwl.basic.clickhouse.service.StatsQueryService;
import com.ycwl.basic.mapper.StatisticsMapper;
import com.ycwl.basic.model.mobile.statistic.req.CommonQueryReq;
import com.ycwl.basic.model.pc.statistics.resp.OrderStatisticsResp;
import com.ycwl.basic.service.pc.StatisticsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author：longbinbin
 * @Date：2024/12/12 14:34
 */
@Service
public class StatisticsServiceImpl implements StatisticsService {

    @Autowired
    private StatsQueryService statsQueryService;
    @Autowired
    private StatisticsMapper statisticsMapper;

    @Override
    public List<HashMap<String, String>> getScanCodeMemberChartAuto(CommonQueryReq query) {
        // 检查时间范围
        if (query.getStartTime() == null || query.getEndTime() == null) {
            // 根据需求处理时间范围：
            // 如果开始和结束时间均为空，则默认为当天0点到23时59分59秒
            // 如果只有一个为空，则往前或往后推24小时
            LocalDateTime now = LocalDateTime.now();

            if (query.getStartTime() == null && query.getEndTime() == null) {
                // 都为空，设置为当天0点到23:59:59
                LocalDateTime startOfDay = now.withHour(0).withMinute(0).withSecond(0).withNano(0);
                LocalDateTime endOfDay = now.withHour(23).withMinute(59).withSecond(59).withNano(0);

                query.setStartTime(Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant()));
                query.setEndTime(Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant()));
            } else if (query.getStartTime() == null) {
                // 开始时间为空，结束时间不为空，往前推24小时
                LocalDateTime endDateTime = query.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                LocalDateTime startDateTime = endDateTime.minusHours(24);

                query.setStartTime(Date.from(startDateTime.atZone(ZoneId.systemDefault()).toInstant()));
            } else {
                // 结束时间为空，开始时间不为空，往后推24小时
                LocalDateTime startDateTime = query.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                LocalDateTime endDateTime = startDateTime.plusHours(24);

                query.setEndTime(Date.from(endDateTime.atZone(ZoneId.systemDefault()).toInstant()));
            }
        }

        // 计算时间差（天数）
        LocalDateTime startDateTime = query.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        LocalDateTime endDateTime = query.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        long daysBetween = ChronoUnit.DAYS.between(startDateTime, endDateTime);

        // 超过7天使用日期级别，否则使用小时级别
        if (daysBetween > 7) {
            return getScanCodeMemberChartByDate(query);
        } else {
            return getScanCodeMemberChartByHour(query);
        }
    }

    /**
     * 按小时统计扫码人数（合并统计数据和订单数据）
     */
    private List<HashMap<String, String>> getScanCodeMemberChartByHour(CommonQueryReq query) {
        // 1. 从 StatsQueryService 获取统计数据（根据配置走 ClickHouse 或 MySQL）
        List<HashMap<String, String>> statsData = statsQueryService.scanCodeMemberChartByHour(query);

        // 2. 从 MySQL 获取订单数据
        List<HashMap<String, String>> orderData = statisticsMapper.orderChartByHourForMerge(query);

        // 3. 获取打印样片页面访问数据
        List<HashMap<String, String>> scanTvData = statsQueryService.printerFromSampleChartByHour(query);

        // 4. 合并数据
        return mergeChartData(statsData, orderData, scanTvData);
    }

    /**
     * 按日期统计扫码人数（合并统计数据和订单数据）
     */
    private List<HashMap<String, String>> getScanCodeMemberChartByDate(CommonQueryReq query) {
        // 1. 从 StatsQueryService 获取统计数据（根据配置走 ClickHouse 或 MySQL）
        List<HashMap<String, String>> statsData = statsQueryService.scanCodeMemberChartByDate(query);

        // 2. 从 MySQL 获取订单数据
        List<HashMap<String, String>> orderData = statisticsMapper.orderChartByDateForMerge(query);

        // 3. 获取打印样片页面访问数据
        List<HashMap<String, String>> scanTvData = statsQueryService.printerFromSampleChartByDate(query);

        // 4. 合并数据
        return mergeChartData(statsData, orderData, scanTvData);
    }

    /**
     * 合并统计数据、订单数据和打印样片访问数据
     * 统计数据包含: t, count
     * 订单数据包含: t, orderCount, orderAmount
     * 打印样片数据包含: t, count
     * 合并结果: t, count, orderCount, orderAmount, scanTvCount
     */
    private List<HashMap<String, String>> mergeChartData(
            List<HashMap<String, String>> statsData,
            List<HashMap<String, String>> orderData,
            List<HashMap<String, String>> scanTvData) {

        // 将订单数据转为 Map 以便快速查找
        Map<String, HashMap<String, String>> orderMap = orderData.stream()
                .collect(Collectors.toMap(
                        m -> String.valueOf(m.get("t")),
                        m -> m,
                        (existing, replacement) -> existing
                ));

        // 将打印样片数据转为 Map 以便快速查找
        Map<String, HashMap<String, String>> scanTvMap = scanTvData.stream()
                .collect(Collectors.toMap(
                        m -> String.valueOf(m.get("t")),
                        m -> m,
                        (existing, replacement) -> existing
                ));

        // 合并数据
        for (HashMap<String, String> stat : statsData) {
            String timeKey = String.valueOf(stat.get("t"));

            // 合并订单数据
            HashMap<String, String> order = orderMap.get(timeKey);
            if (order != null) {
                stat.put("orderCount", String.valueOf(order.get("orderCount")));
                stat.put("orderAmount", String.valueOf(order.get("orderAmount")));
            } else {
                stat.put("orderCount", "0");
                stat.put("orderAmount", "0");
            }

            // 合并打印样片访问数据
            HashMap<String, String> scanTv = scanTvMap.get(timeKey);
            if (scanTv != null) {
                stat.put("scanTvCount", String.valueOf(scanTv.get("count")));
            } else {
                stat.put("scanTvCount", "0");
            }
        }

        return statsData;
    }

    @Override
    public OrderStatisticsResp getOrderStatistics(CommonQueryReq query) {
        // 时间参数兜底与规范化
        if (query.getStartTime() == null && query.getEndTime() == null) {
            // 默认查询今天：00:00:00 - 23:59:59
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime startOfDay = now.withHour(0).withMinute(0).withSecond(0).withNano(0);
            LocalDateTime endOfDay = now.withHour(23).withMinute(59).withSecond(59).withNano(0);
            query.setStartTime(Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant()));
            query.setEndTime(Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant()));
        } else {
            if (query.getEndTime() != null) {
                // 保证 endTime 为当天最后一秒
                LocalDateTime endDateTime = query.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                LocalDateTime endOfDay = endDateTime.withHour(23).withMinute(59).withSecond(59).withNano(0);
                query.setEndTime(Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant()));
            } else if (query.getStartTime() != null) {
                // 仅传 startTime 时，将 endTime 置为 startTime 当天的 23:59:59
                LocalDateTime startDateTime = query.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                LocalDateTime endOfStartDay = startDateTime.withHour(23).withMinute(59).withSecond(59).withNano(0);
                query.setEndTime(Date.from(endOfStartDay.atZone(ZoneId.systemDefault()).toInstant()));
            }
        }
        return statisticsMapper.getOrderStatistics(query);
    }
}