package com.hzs.member.achieve.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzs.common.core.constant.*;
import com.hzs.common.core.enums.EExpandCapMethod;
import com.hzs.common.core.enums.ESystemConfig;
import com.hzs.common.core.enums.EYesNo;
import com.hzs.common.core.service.RedisService;
import com.hzs.common.core.utils.ComputeUtil;
import com.hzs.common.core.utils.DateUtils;
import com.hzs.common.core.utils.StringUtils;
import com.hzs.common.domain.member.achieve.CuMemberSettlePeriod;
import com.hzs.common.domain.member.achieve.CuMemberSettlePeriodDetail;
import com.hzs.common.domain.member.achieve.ext.CuMemberSettlePeriodExt;
import com.hzs.common.domain.system.base.BdCountry;
import com.hzs.member.achieve.mapper.CuMemberSettlePeriodMapper;
import com.hzs.member.achieve.param.MemberPeriodParam;
import com.hzs.member.achieve.service.ICuMemberSettlePeriodDetailService;
import com.hzs.member.achieve.service.ICuMemberSettlePeriodService;
import com.hzs.system.base.ICountryServiceApi;
import com.hzs.system.base.ISystemConfigServiceApi;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * <p>
 * 会员结算期间 服务实现类
 * </p>
 *
 * @author hzs
 * @since 2022-10-26
 */
@Service
public class CuMemberSettlePeriodServiceImpl extends ServiceImpl<CuMemberSettlePeriodMapper, CuMemberSettlePeriod> implements ICuMemberSettlePeriodService {


    private RedisService redisService;

    @Autowired
    private ICuMemberSettlePeriodDetailService cuMemberSettlePeriodDetailService;

    @DubboReference
    private ICountryServiceApi countryServiceApi;

    @DubboReference
    private ISystemConfigServiceApi systemConfigServiceApi;

    @Autowired
    public void setRedisService(RedisService redisService) {
        this.redisService = redisService;
    }

    @Override
    public void initCuMemberPeriod(String settleDate) {
        // 分为周结和秒结的
        List<Integer> weekSettleCountry = new ArrayList<>();
        List<Integer> daySettleCountry = new ArrayList<>();
        packageSettleCountry(weekSettleCountry, daySettleCountry);
        List<CuMemberSettlePeriodDetail> cuMemberSettlePeriodDetailList = new ArrayList<>();
        Date startDate = DateUtils.parseStringToDate("2021-01-12");
        Date endDate =  DateUtils.parseStringToDate(settleDate);
        Map<String, CuMemberSettlePeriod> memberSettlePeriodMap = queryCuMemberSettlePeriod(startDate,
                endDate);
        List<String> periodList = new ArrayList<>();
        while (DateUtils.compareDate(endDate, startDate) >=0) {
            if (daySettleCountry.size() > 0) {
                CuMemberSettlePeriod cuMemberSettlePeriod = memberSettlePeriodMap.get(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, startDate));
                for (Integer pkCountry : daySettleCountry) {
                    CuMemberSettlePeriodDetail cuMemberSettlePeriodDetail = CuMemberSettlePeriodDetail.builder()
                            .settleCycle(EExpandCapMethod.DAY_SETTLE.getValue())
                            .startPeriod(cuMemberSettlePeriod.getPkId())
                            .endPeriod(cuMemberSettlePeriod.getPkId())
                            .isSettle(EYesNo.YES.getIntValue())
                            .isPublish(EYesNo.YES.getIntValue())
                            .isGrant(EYesNo.YES.getIntValue())
                            .isWithdrawal(EYesNo.YES.getIntValue())
                            .build();
                    cuMemberSettlePeriodDetail.setPkCountry(pkCountry);
                    cuMemberSettlePeriodDetail.setPkCreator(MagicNumberConstants.PK_ADMIN);
                    cuMemberSettlePeriodDetailList.add(cuMemberSettlePeriodDetail);
                }
            }

            // 查询期间，结算日期前10天 到现在
            if (weekSettleCountry.size() > 0) {
                // 获得周期第一天，最后一天
                Integer startPeriod = memberSettlePeriodMap.get(DateUtils.getRecentlyTuesday(startDate)).getPkId();
                Integer endPeriod = memberSettlePeriodMap.get(DateUtils.getRecentlyMonday(startDate)).getPkId();
                String periodKey = startPeriod.toString() + endPeriod;
                if (!periodList.contains(periodKey)) {
                    for (Integer pkCountry : weekSettleCountry) {
                        CuMemberSettlePeriodDetail cuMemberSettlePeriodDetail = CuMemberSettlePeriodDetail.builder()
                                .settleCycle(EExpandCapMethod.WEEK_SETTLE.getValue())
                                .startPeriod(startPeriod)
                                .endPeriod(endPeriod)
                                .isSettle(EYesNo.YES.getIntValue())
                                .isPublish(EYesNo.YES.getIntValue())
                                .isGrant(EYesNo.YES.getIntValue())
                                .isWithdrawal(EYesNo.YES.getIntValue())
                                .build();
                        cuMemberSettlePeriodDetail.setPkCountry(pkCountry);
                        cuMemberSettlePeriodDetail.setPkCreator(MagicNumberConstants.PK_ADMIN);
                        cuMemberSettlePeriodDetailList.add(cuMemberSettlePeriodDetail);
                    }
                    periodList.add(periodKey);
                }
            }
            startDate = DateUtils.afterDate(1, ChronoUnit.DAYS, startDate);
        }

        cuMemberSettlePeriodDetailService.saveBatch(cuMemberSettlePeriodDetailList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CuMemberSettlePeriod getCuMemberSettlePeriodByDate(String date) {
        String key = CacheConstants.CU_MEMBER_SETTLE_PERIOD + date;
        CuMemberSettlePeriod cuMemberSettlePeriod = redisService.getCacheObject(key);
        if (cuMemberSettlePeriod == null) {
            cuMemberSettlePeriod = getCuMemberSettlePeriod(date);
            if (cuMemberSettlePeriod != null) {
                redisService.setCacheObject(key, cuMemberSettlePeriod);
            } else {
                QueryWrapper<CuMemberSettlePeriod> queryWrapper1 = new QueryWrapper<>();
                queryWrapper1.select("max(pk_id) pk_id,max(settle_date) settle_date");
                cuMemberSettlePeriod = baseMapper.selectOne(queryWrapper1);
                if (DateUtils.compareDateAfter(DateUtils.parseDate(date), cuMemberSettlePeriod.getSettleDate())) {
                    int addDayNum = 8 - DateUtils.getRecentlyDay(cuMemberSettlePeriod.getSettleDate()) + MagicNumberConstants.PERIOD_AUTO_INCREASE;
                    while (true) {
                        Date laseDate = DateUtils.afterDate(addDayNum, ChronoUnit.DAYS, cuMemberSettlePeriod.getSettleDate());
                        // 验证最后一天是否为周一，周一跳出循环
                        if (DateUtils.getRecentlyDay(laseDate) == 1) {
                            break;
                        }
                        addDayNum++;
                    }
                    // 分为周结和秒结的
                    List<Integer> weekSettleCountry = new ArrayList<>();
                    List<Integer> daySettleCountry = new ArrayList<>();
                    packageSettleCountry(weekSettleCountry, daySettleCountry);
                    List<CuMemberSettlePeriodDetail> cuMemberSettlePeriodDetailList = new ArrayList<>();
                    for (int i = 0; i < addDayNum; i++) {
                        Date tomorrow = DateUtils.afterDate(i + 1, ChronoUnit.DAYS, cuMemberSettlePeriod.getSettleDate());
                        CuMemberSettlePeriod addSettlePeriod = CuMemberSettlePeriod.builder()
                                .settleDate(tomorrow)
                                .pkCreator(MagicNumberConstants.PK_ADMIN)
                                .build();
                        save(addSettlePeriod);
                        if (daySettleCountry.size() > 0) {
                            for (Integer pkCountry : daySettleCountry) {
                                CuMemberSettlePeriodDetail cuMemberSettlePeriodDetail = CuMemberSettlePeriodDetail.builder()
                                        .settleCycle(EExpandCapMethod.DAY_SETTLE.getValue())
                                        .startPeriod(addSettlePeriod.getPkId())
                                        .endPeriod(addSettlePeriod.getPkId())
                                        .build();
                                cuMemberSettlePeriodDetail.setPkCountry(pkCountry);
                                cuMemberSettlePeriodDetail.setPkCreator(MagicNumberConstants.PK_ADMIN);
                                cuMemberSettlePeriodDetailList.add(cuMemberSettlePeriodDetail);
                            }
                        }
                    }
                    // 查询期间，结算日期前10天 到现在
                    if (weekSettleCountry.size() > 0) {
                        Map<String, CuMemberSettlePeriod> memberSettlePeriodMap = queryCuMemberSettlePeriod(DateUtils.beforeDate(10, ChronoUnit.DAYS, cuMemberSettlePeriod.getSettleDate()), DateUtils.afterDate(addDayNum, ChronoUnit.DAYS, cuMemberSettlePeriod.getSettleDate()));
                        List<String> periodList = new ArrayList<>();
                        for (int i = 0; i < addDayNum; i++) {
                            Date tomorrow = DateUtils.afterDate(i + 1, ChronoUnit.DAYS, cuMemberSettlePeriod.getSettleDate());
                            // 获得周期第一天，最后一天
                            Integer startPeriod = memberSettlePeriodMap.get(DateUtils.getRecentlyTuesday(tomorrow)).getPkId();
                            Integer endPeriod = memberSettlePeriodMap.get(DateUtils.getRecentlyMonday(tomorrow)).getPkId();
                            String periodKey = startPeriod.toString() + endPeriod;
                            if (!periodList.contains(periodKey)) {
                                for (Integer pkCountry : weekSettleCountry) {
                                    CuMemberSettlePeriodDetail cuMemberSettlePeriodDetail = CuMemberSettlePeriodDetail.builder()
                                            .settleCycle(EExpandCapMethod.WEEK_SETTLE.getValue())
                                            .startPeriod(startPeriod)
                                            .endPeriod(endPeriod)
                                            .build();
                                    cuMemberSettlePeriodDetail.setPkCountry(pkCountry);
                                    cuMemberSettlePeriodDetail.setPkCreator(MagicNumberConstants.PK_ADMIN);
                                    cuMemberSettlePeriodDetailList.add(cuMemberSettlePeriodDetail);
                                }
                                periodList.add(periodKey);
                            }
                        }
                    }
                    cuMemberSettlePeriodDetailService.saveBatch(cuMemberSettlePeriodDetailList);
                    cuMemberSettlePeriod = getCuMemberSettlePeriod(date);
                } else {
                    return null;
                }
            }
        }
        return cuMemberSettlePeriod;
    }

    private void packageSettleCountry(List<Integer> weekSettleCountry, List<Integer> daySettleCountry) {
        Map<Integer, BdCountry> allCountryMap = countryServiceApi.getAllCountryMap().getData();
        for (Integer pkCountry : allCountryMap.keySet()) {
            String value = systemConfigServiceApi.getBonusSystemConfig(pkCountry, ESystemConfig.EXPAND_CAP_METHOD.getKey()).getData();
            // 周结
            if (StringUtils.isNotEmpty(value) && Objects.equals(Integer.toString(EExpandCapMethod.WEEK_SETTLE.getValue()), value)) {
                weekSettleCountry.add(pkCountry);
            } else {
                daySettleCountry.add(pkCountry);
            }
        }
    }

    @Override
    public CuMemberSettlePeriodExt getCuMemberSettlePeriod(Integer pkCountry, Date date) {
        return baseMapper.queryMemberSettlePeriod(pkCountry, date);
    }

    private CuMemberSettlePeriod getCuMemberSettlePeriod(String date) {
        QueryWrapper<CuMemberSettlePeriod> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("SETTLE_DATE", DateUtils.parseStringToDate(date));
        return baseMapper.selectOne(queryWrapper);
    }

    /*
     * @description: 获取期间，开始时间到结束时间
     * @author: sui q
     * @date: 2023/7/29 9:43
     * @param: null null
     **/
    private Map<String, CuMemberSettlePeriod> queryCuMemberSettlePeriod(Date startDate, Date endDate) {
        QueryWrapper<CuMemberSettlePeriod> queryWrapper = new QueryWrapper<>();
        queryWrapper.ge("SETTLE_DATE", startDate);
        queryWrapper.le("SETTLE_DATE", endDate);
        List<CuMemberSettlePeriod> memberSettlePeriodList = baseMapper.selectList(queryWrapper);
        Map<String, CuMemberSettlePeriod> cuMemberSettlePeriodMap = new HashMap<>();
        memberSettlePeriodList.forEach(cuMemberSettlePeriod ->
                cuMemberSettlePeriodMap.put(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, cuMemberSettlePeriod.getSettleDate()), cuMemberSettlePeriod));
        return cuMemberSettlePeriodMap;
    }

    @Override
    public List<CuMemberSettlePeriod> queryCuMemberSettlePeriod() {
        QueryWrapper<CuMemberSettlePeriod> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("PK_ID,SETTLE_DATE");
        queryWrapper.orderByDesc(SystemFieldConstants.PK_ID);
        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public List<CuMemberSettlePeriodExt> queryCuMemberSettlePeriod(MemberPeriodParam periodParam) {
        return baseMapper.queryMemberSettlePeriodByCondition(periodParam);
    }

    @Override
    public void updateCuMemberSettlePeriodByDate(CuMemberSettlePeriodExt cuMemberSettlePeriodByDate) {
//        baseMapper.updateById(cuMemberSettlePeriodByDate);
        cuMemberSettlePeriodDetailService.updateCuMemberSettlePeriodDetailByPeriod(cuMemberSettlePeriodByDate);
//        String key = CacheConstants.CU_MEMBER_SETTLE_PERIOD + DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, cuMemberSettlePeriodByDate.getSettleDate());
//        redisService.deleteObjectByKey(key);
    }

}
