package com.kym.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.github.pagehelper.PageHelper;
import com.kym.common.utils.CommUtil;
import com.kym.entity.DailyStat;
import com.kym.entity.StatSyncLog;
import com.kym.entity.common.PageBean;
import com.kym.entity.queryParams.DailyStatQueryParam;
import com.kym.entity.vo.DailyStatVo;
import com.kym.mapper.DailyStatMapper;
import com.kym.service.*;
import com.kym.service.cache.KymCache;
import com.kym.service.mybatisplus.MyBaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 日统计表 服务实现类
 *
 * @author skyline
 * @since 2025-02-19
 */
@Slf4j
@Service
public class DailyStatServiceImpl extends MyBaseServiceImpl<DailyStatMapper, DailyStat> implements DailyStatService {

    private final WashOrderService washOrderService;
    private final UserService userService;
    private final SplitRecordService splitRecordService;
    private final WashStationService washStationService;
    private final StatSyncLogService statSyncLogService;

    public DailyStatServiceImpl(WashOrderService washOrderService, UserService userService,
                                SplitRecordService splitRecordService, WashStationService washStationService,
                                StatSyncLogService statSyncLogService) {
        this.washOrderService = washOrderService;
        this.userService = userService;
        this.splitRecordService = splitRecordService;
        this.washStationService = washStationService;
        this.statSyncLogService = statSyncLogService;
    }

    @Override
    public PageBean<DailyStatVo> listDailyStat(DailyStatQueryParam params) {
        var query = lambdaQuery()
                .eq(CommUtil.isNotEmptyAndNull(params.getStationId()),
                        DailyStat::getStationId, params.getStationId())
                .ge(params.getStartDate() != null,
                        DailyStat::getStatDate, params.getStartDate() != null ? params.getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE) : null)
                .le(params.getEndDate() != null,
                        DailyStat::getStatDate, params.getEndDate() != null ? params.getEndDate().format(DateTimeFormatter.ISO_LOCAL_DATE) : null)
                .orderByDesc(DailyStat::getStatDate);

        var page = PageHelper.startPage(params.getPageNum(), params.getPageSize());
        var list = query.list();

        var voList = list.stream().map(item -> {
            var vo = new DailyStatVo();
            BeanUtils.copyProperties(item, vo);
            vo.setStationName(KymCache.INSTANCE.getStationNameById(item.getStationId()));
            return vo;
        }).toList();

        var bean = new PageBean<>(voList);
        bean.setPages(page.getPages());
        bean.setPageNum(page.getPageNum());
        bean.setPageSize(page.getPageSize());
        bean.setTotal(page.getTotal());
        return bean;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncDailyStat(String statDate) {
        LocalDate statDay = LocalDate.parse(statDate, DateTimeFormatter.ISO_LOCAL_DATE);
        log.info("手动同步日统计: {}", statDate);

        // 一次性聚合所有数据
        var amountMap = washOrderService.sumAmountByDate(statDay);
        var registerMap = userService.countDailyRegister(statDay);
        var ordersCountMap = washOrderService.countDailyOrders(statDay);
        var rechargeIncomeMap = splitRecordService.sumDailyRechargeIncome(statDay);
        var crossIncomeMap = splitRecordService.sumDailyCrossIncome(statDay);
        var crossExpendMap = splitRecordService.sumDailyCrossExpend(statDay);
        var refundMap = splitRecordService.sumDailyRefund(statDay);
        var rechargeCountMap = splitRecordService.countDailyRecharge(statDay);
        var refundCountMap = splitRecordService.countDailyRefund(statDay);
        var activeUserMap = washOrderService.countDailyActiveUsers(statDay);

        // 总入账 = 充值收入 + 跨店收入
        var incomeMap = new HashMap<>(rechargeIncomeMap);
        crossIncomeMap.forEach((k, v) -> incomeMap.merge(k, v, Integer::sum));

        // 收集所有出现过的站点（过滤掉无归属的null和"未分配"占位符）
        var allStationIds = Stream.of(amountMap, registerMap, ordersCountMap, incomeMap,
                        crossIncomeMap, crossExpendMap, refundMap, rechargeCountMap, refundCountMap, activeUserMap)
                .flatMap(m -> m.keySet().stream())
                .filter(s -> s != null && !"未分配".equals(s))
                .collect(Collectors.toSet());

        long operatorId = 0;
        String operatorName = "系统";
        try {
            operatorId = StpUtil.getLoginIdAsLong();
            operatorName = StpUtil.getLoginIdAsString();
        } catch (Exception ignored) {
        }

        var now = LocalDateTime.now();
        var statList = new ArrayList<DailyStat>();

        for (var stationId : allStationIds) {
            try {
                var stat = new DailyStat();
                stat.setStatDate(statDate);
                stat.setStationId(stationId);
                stat.setConsumption(amountMap.getOrDefault(stationId, 0));
                stat.setRegistrations(registerMap.getOrDefault(stationId, 0));
                stat.setOrdersCount(ordersCountMap.getOrDefault(stationId, 0));
                stat.setTotalIncome(incomeMap.getOrDefault(stationId, 0));
                stat.setCrossIncome(crossIncomeMap.getOrDefault(stationId, 0));
                stat.setCrossExpend(crossExpendMap.getOrDefault(stationId, 0));
                stat.setTotalRefund(refundMap.getOrDefault(stationId, 0));
                stat.setRechargeCount(rechargeCountMap.getOrDefault(stationId, 0));
                stat.setRefundCount(refundCountMap.getOrDefault(stationId, 0));
                stat.setActiveUserCount(activeUserMap.getOrDefault(stationId, 0));
                statList.add(stat);

                var syncLog = new StatSyncLog()
                        .setStatType(StatSyncLog.TYPE_DAILY)
                        .setStatKey(statDate)
                        .setStationId(stationId)
                        .setSyncStatus(StatSyncLog.STATUS_SUCCESS)
                        .setSyncBy(operatorId)
                        .setSyncByName(operatorName)
                        .setStartTime(now)
                        .setEndTime(LocalDateTime.now());
                statSyncLogService.save(syncLog);
            } catch (Exception e) {
                log.error("同步日统计失败: statDate={}, stationId={}", statDate, stationId, e);
                var syncLog = new StatSyncLog()
                        .setStatType(StatSyncLog.TYPE_DAILY)
                        .setStatKey(statDate)
                        .setStationId(stationId)
                        .setSyncStatus(StatSyncLog.STATUS_FAILED)
                        .setSyncBy(operatorId)
                        .setSyncByName(operatorName)
                        .setErrorMsg(e.getMessage())
                        .setStartTime(now)
                        .setEndTime(LocalDateTime.now());
                statSyncLogService.save(syncLog);
            }
        }

        if (!statList.isEmpty()) {
            replaceBatch(statList);
        }
        log.info("日统计同步完成: {}, 站点数: {}", statDate, statList.size());
    }
}
