package digital.laboratory.platform.imr.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import digital.laboratory.platform.imr.component.DateUtils;
import digital.laboratory.platform.imr.entity.DrugCaseInfo;
import digital.laboratory.platform.imr.entity.DrugHandingOverApply;
import digital.laboratory.platform.imr.entity.DrugMaterialInfo;
import digital.laboratory.platform.imr.mapper.DrugHandingOverApplyMapper;
import digital.laboratory.platform.imr.mapper.DrugMaterialInfoMapper;
import digital.laboratory.platform.imr.query.DrugStatisticQuery;
import digital.laboratory.platform.imr.service.CommonFeignService;
import digital.laboratory.platform.imr.service.DrugCaseInfoService;
import digital.laboratory.platform.imr.service.DrugHandingOverApplyService;
import digital.laboratory.platform.imr.service.DrugHandingOverStatisticService;
import digital.laboratory.platform.imr.vo.DrugMaterialInfoVO;
import digital.laboratory.platform.imr.vo.DrugStatisticVO;
import digital.laboratory.platform.sys.entity.SysOrg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 毒品库送缴量统计 服务处接口 -- 实现类
 */
@Service
public class DrugHandingOverStatisticServiceImpl implements DrugHandingOverStatisticService {

    @Resource
    private DrugMaterialInfoMapper drugMaterialInfoMapper;

    @Resource
    private DrugCaseInfoService drugCaseInfoService;

    @Resource
    private DrugHandingOverApplyService drugHandingOverApplyService;

    @Resource
    private CommonFeignService commonFeignService;
    @Autowired
    private DrugHandingOverApplyMapper drugHandingOverApplyMapper;

    /**
     * 获取统计图的数据， 根据时间范围, 送缴单位，毒品种类返回数据
     * @param query
     * @return
     */
    @Override
    public DrugStatisticVO statistic(DrugStatisticQuery query) {
        DrugStatisticVO drugStatisticVO = new DrugStatisticVO();
        // 创建 CompletableFuture 用于异步执行 buildLineChartData 和 buildBarChartData
        CompletableFuture<Void> lineChartFuture = CompletableFuture.runAsync(() -> buildLineChartData(query, drugStatisticVO));
        CompletableFuture<Void> barChartFuture = CompletableFuture.runAsync(() -> buildBarChartData(query, drugStatisticVO));

        // 等待两个任务完成
        CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(lineChartFuture, barChartFuture);

        try {
            // 等待所有异步任务执行完成
            combinedFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            // 处理异常
            e.printStackTrace();
        }

        // 返回最终构建好的 DrugStatisticVO
        return drugStatisticVO;
    }

    /**
     * 构建柱状图的数据
     *
     * @param query
     * @param drugStatisticVO
     * @return
     */
    private void buildBarChartData(DrugStatisticQuery query, DrugStatisticVO drugStatisticVO) {
        List<List<Object>> barChartData = new ArrayList<>();
        List<Object> orgNameList = new ArrayList<>();
        List<Object> dataList = new ArrayList<>();

        // 存储机构的map
        Map<String, SysOrg> sysOrgMap = new HashMap<>();
        // 根据案件表取所有的送缴单位
        if (StrUtil.isBlank(query.getOrgId())) {
            List<DrugHandingOverApply> drugHandingOverApplies = drugHandingOverApplyService.list();
            sysOrgMap = drugHandingOverApplies.stream()
                    .collect(Collectors.toMap(
                                    DrugHandingOverApply::getHandingOverOrg,
                                    drugHandingOverApply -> commonFeignService.remoteGetSysOrg(drugHandingOverApply.getHandingOverOrg()),
                                    (existing, replacement) -> existing
                            )
                    );
        } else {
            List<SysOrg> sysOrgList = commonFeignService.remoteGetSysOrgByParentId(query.getOrgId());
            sysOrgMap = sysOrgList.stream().collect(Collectors.toMap(SysOrg::getOrgId, Function.identity()));
        }
        // 根据时间点获取检材
        List<DrugMaterialInfoVO> drugMaterialInfoVOList = drugMaterialInfoMapper.getDrugMaterialVO(
                Wrappers.<DrugMaterialInfo>query()
                        .ge(query.getStartDate() != null, "dc.handing_over_date", query.getStartDate())
                        .le(query.getEndDate() != null, "dc.handing_over_date", query.getEndDate())
        );
        Map<String, List<DrugMaterialInfoVO>> groupByHandingOverOrgMap = drugMaterialInfoVOList.stream().collect(Collectors.groupingBy(DrugMaterialInfoVO::getHandingOverOrg));
        sysOrgMap.forEach((orgId, sysOrg) -> {
            List<DrugMaterialInfoVO> voList = groupByHandingOverOrgMap.get(orgId);
            if (CollUtil.isNotEmpty(voList)) {
                orgNameList.add(sysOrg.getAlias());
                int size = voList.size();
                dataList.add(size);
            }
        });

        barChartData.add(orgNameList);
        barChartData.add(dataList);
        drugStatisticVO.setBarChartDataSum(dataList.stream().mapToInt(obj -> (Integer) obj).sum());
        drugStatisticVO.setBarChartDataList(barChartData);
//        return barChartData;
    }

    /**
     * 构建折线图的数据
     *
     * @param query
     * @param drugStatisticVO
     * @return
     */
    private void buildLineChartData(DrugStatisticQuery query, DrugStatisticVO drugStatisticVO) {
        List<List<Object>> lineChartData = new ArrayList<>(); // 存储结果值
        List<Object> monthsList = new ArrayList<>(); // 存储月份
        List<Object> dataList = new ArrayList<>(); // 对应月份送缴的数量
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DateUtils.yyyy_MM); // 规定日期格式
        LocalDate startDate = query.getStartDate();
        LocalDate endDate = query.getEndDate();

        // 判断当前查询的模式
        if (startDate == null && endDate == null) {
            // 默认统计 一年内的
            LocalDate currentDate = LocalDate.now();
            for (int i = 11; i >= 0; i--) {
                fillLineChartData(monthsList, dataList, dateTimeFormatter, currentDate, query.getOrgId(), i);
            }
        } else if (startDate != null && endDate != null) {
            // 计算查询开始时间和接受时间相差的月份数量
            long between = ChronoUnit.MONTHS.between(startDate, endDate);
            for (int i = (int) (between -1); i >= 0; i--) {
                fillLineChartData(monthsList, dataList, dateTimeFormatter, startDate, query.getOrgId(), i);
            }
        }  else if (startDate == null && endDate != null) {
            // 只返回1年内的数据
            for (int i = 11; i >= 0; i--) {
                fillLineChartData(monthsList, dataList, dateTimeFormatter, endDate, query.getOrgId(), i);
            }
        } else {
            // 只返回1年内的数据
            for (int i = 11; i >= 0; i--) {
                fillLineChartData(monthsList, dataList, dateTimeFormatter, startDate.minusMonths(11), query.getOrgId(), i);
            }
        }
        lineChartData.add(monthsList);
        lineChartData.add(dataList);
        drugStatisticVO.setLineChartDataSum(dataList.stream().mapToInt(obj -> (Integer) obj).sum());
        drugStatisticVO.setLineChartDataList(lineChartData);
    }

    /**
     * 填充折线图数据
     *
     * @param monthsList 月份列表，用于存储月份字符串
     * @param dataList 数据列表，用于存储数据对象
     * @param dateTimeFormatter 日期时间格式化器，用于格式化日期
     * @param startDate 起始日期
     * @param i 月份偏移量
     */
    private void fillLineChartData(List<Object> monthsList, List<Object> dataList, DateTimeFormatter dateTimeFormatter, LocalDate startDate, String orgId, int i) {
        LocalDate localDate = startDate.minusMonths(i);
        LocalDate withDayOfMonth = localDate.withDayOfMonth(1);
        dataList.add(
                drugMaterialInfoMapper.getDrugMaterialVO(
                        Wrappers.<DrugMaterialInfo>query()
                                .eq(StrUtil.isNotBlank(orgId), "dhoa.handing_over_org", orgId)
                                .ge("dhoa.handing_over_date", withDayOfMonth.atStartOfDay())
                                .le("dhoa.handing_over_date",
                                        withDayOfMonth.plusMonths(1).minusDays(1).atTime(LocalTime.MAX))
                ).size()
        );
        monthsList.add(localDate.format(dateTimeFormatter));
    }
}
