package com.hzs.bonus.bonus.service.impl;

import com.hzs.bonus.account.service.ICuMemberAccountService;
import com.hzs.bonus.account.service.ICuMemberTradeDetailService;
import com.hzs.bonus.account.service.ICuMemberTradeService;
import com.hzs.bonus.achieve.service.ICuMemberSettlePeriodService;
import com.hzs.bonus.bonus.service.IBonusGrantService;
import com.hzs.bonus.bonus.service.ICuMemberBonusService;
import com.hzs.bonus.pub.tool.MemberToolsHandler;
import com.hzs.common.core.constant.MagicNumberConstants;
import com.hzs.common.core.enums.*;
import com.hzs.common.core.utils.ComputeUtil;
import com.hzs.common.core.utils.DateUtils;
import com.hzs.common.domain.member.account.CuMemberTrade;
import com.hzs.common.domain.member.account.CuMemberTradeDetail;
import com.hzs.common.domain.member.achieve.ext.CuMemberSettlePeriodExt;
import com.hzs.common.domain.member.bonus.CuMemberBonus;
import com.hzs.common.domain.system.base.BdCountry;
import com.hzs.common.domain.system.config.BdAccount;
import com.hzs.system.base.ICountryServiceApi;
import com.hzs.system.base.ICurrencyServiceApi;
import com.hzs.system.base.dto.CurrencyDTO;
import com.hzs.system.config.IAccountServiceApi;
import lombok.extern.slf4j.Slf4j;
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.math.BigDecimal;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * 奖金发放实现类
 */
@Slf4j
@Service
public class BonusGrantServiceImpl implements IBonusGrantService {

    @DubboReference
    IAccountServiceApi iAccountServiceApi;

    @Autowired
    private ICuMemberBonusService iCuMemberBonusService;
    @Autowired
    private ICuMemberSettlePeriodService iCuMemberSettlePeriodService;
    @Autowired
    private ICuMemberTradeService iCuMemberTradeService;
    @Autowired
    private ICuMemberTradeDetailService iCuMemberTradeDetailService;
    @Autowired
    private ICuMemberAccountService iCuMemberAccountService;
    @Autowired
    private MemberToolsHandler memberToolsHandler;

    @DubboReference
    ICountryServiceApi iCountryServiceApi;
    @DubboReference
    ICurrencyServiceApi iCurrencyServiceApi;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void publishBonusByPeriodEveryDay() {
        Map<Integer, BdCountry> integerBdCountryMap = iCountryServiceApi.getAllCountryMap().getData();
        if (integerBdCountryMap.size() > 0) {
            for (Integer pkCountry : integerBdCountryMap.keySet()) {
                String settleDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.beforeDate(1, ChronoUnit.DAYS, DateUtils.currentDate()));
                CuMemberSettlePeriodExt cuMemberSettlePeriod = getCuMemberSettlePeriod(pkCountry, settleDate);
                log.info("公布奖金参数, settleDate: {}, ", settleDate);
                // 设置不公布后不能自动公布奖金
                if (EYesNo.PROHIBIT.getIntValue() == cuMemberSettlePeriod.getIsPublish()) {
                    return;
                }
                log.info("公布奖金期数状态, isPublish: {}, ", cuMemberSettlePeriod.getIsPublish());
                publishBonus(cuMemberSettlePeriod);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void grantWithdrawBonusByPeriodEveryDay() {
        // 会员只15、30号发：
        // 24-7 : 15号发
        // 8-23 : 30号发 （每月最后一天）

        // 当前日期
        Date nowDate = DateUtils.currentDate();
        // 当前日期的天
        int dateDD = Integer.parseInt(DateUtils.parseDateTimeToStr(DateUtils.DD, nowDate));
        // 当月最后一天
        int monthLast = Integer.parseInt(DateUtils.parseDateTimeToStr(DateUtils.DD, DateUtils.currentMonthLastDate(nowDate)));
        // 发放开始时间
        String settleDate = null;
        // 发放结束时间
        String endSettleDate = null;

        Map<Integer, BdCountry> integerBdCountryMap = iCountryServiceApi.getAllCountryMap().getData();
        if (integerBdCountryMap.size() > 0) {
            for (Integer pkCountry : integerBdCountryMap.keySet()) {
                if (dateDD == 15) {
                    // 15号，发 上月24号 到 本月7号
                    settleDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.setDays(DateUtils.addMonths(nowDate, -1), 24));
                    endSettleDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.setDays(nowDate, 24));
                } else if (dateDD == monthLast) {
                    // 当月最后一天，发 本月8号 到 本月23号
                    settleDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.setDays(nowDate, 8));
                    endSettleDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.setDays(nowDate, 23));
                }

                if (null != settleDate) {
                    // 开始结束时间都有值，才进行发放
                    // 发放奖金
                    grantBonusByPeriod(pkCountry, settleDate, endSettleDate);
                    // 奖金可以提现
                    withdrawalBonusByPeriod(pkCountry, settleDate, endSettleDate);
                }
            }
        }
    }

    /*
     * 公布奖金
     **/
    private void publishBonus(CuMemberSettlePeriodExt cuMemberSettlePeriod) {
        if (EYesNo.YES.getIntValue() == cuMemberSettlePeriod.getIsPublish()) {
            return;
        }

        log.info("公布奖金开始, periodId: {}, ", cuMemberSettlePeriod.getPkId());
        // 更新奖金状态（cu_member_bonus）
        iCuMemberBonusService.updateCuMemberBonusStatus(null, EGrantStatus.PUBLISHED.getValue(), EGrantStatus.SETTLED.getValue(),
                cuMemberSettlePeriod.getPkId(), cuMemberSettlePeriod.getPkId());
        // 更新期间表状态（cu_member_settle_period_detail）
        cuMemberSettlePeriod.setIsPublish(EYesNo.YES.getIntValue());
        cuMemberSettlePeriod.setPublishDate(DateUtils.currentDateTime());
        iCuMemberSettlePeriodService.updateCuMemberSettlePeriodByDate(cuMemberSettlePeriod);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void publishBonusByPeriod(Integer pkCountry, String settleDate) {
        CuMemberSettlePeriodExt cuMemberSettlePeriod = getCuMemberSettlePeriod(pkCountry, settleDate);
        publishBonus(cuMemberSettlePeriod);
    }

    private CuMemberSettlePeriodExt getCuMemberSettlePeriod(Integer pkCountry, String settleDate) {
        CuMemberSettlePeriodExt cuMemberSettlePeriodByDate = iCuMemberSettlePeriodService.getCuMemberSettlePeriod(pkCountry, DateUtils.parseStringToDate(settleDate));
        cuMemberSettlePeriodByDate.setPkModified(MagicNumberConstants.PK_ADMIN);
        cuMemberSettlePeriodByDate.setModifiedTime(DateUtils.currentDateTime());
        return cuMemberSettlePeriodByDate;
    }

    private List<CuMemberSettlePeriodExt> getCuMemberSettlePeriod(Integer pkCountry, String settleDate, String endSettleDate) {
        Date nowDate = DateUtils.currentDateTime();
        List<CuMemberSettlePeriodExt> cuMemberSettlePeriodList = iCuMemberSettlePeriodService.listCuMemberSettlePeriod(pkCountry, DateUtils.parseStringToDate(settleDate), DateUtils.parseStringToDate(endSettleDate));
        for (CuMemberSettlePeriodExt cuMemberSettlePeriodExt : cuMemberSettlePeriodList) {
            cuMemberSettlePeriodExt.setPkModified(MagicNumberConstants.PK_ADMIN);
            cuMemberSettlePeriodExt.setModifiedTime(nowDate);
        }
        return cuMemberSettlePeriodList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean grantBonusByPeriod(Integer pkCountry, String settleDate, String endSettleDate) {
        // 奖金发放范围期间
        List<CuMemberSettlePeriodExt> cuMemberSettlePeriodList = getCuMemberSettlePeriod(pkCountry, settleDate, endSettleDate);

        Date currentDateTime = DateUtils.currentDateTime();
        Map<Integer, BdAccount> bdAccountValueMap = iAccountServiceApi.getAccountMapByCountry(pkCountry).getData();

        for (CuMemberSettlePeriodExt cuMemberSettlePeriod : cuMemberSettlePeriodList) {
            if (EYesNo.YES.getIntValue() == cuMemberSettlePeriod.getIsGrant()) {
                // 已经发放，则跳过
                continue;
            }
            String settleDateStr = DateUtils.parseDateTimeToStr(DateUtils.YYYY_MM_DD, cuMemberSettlePeriod.getSettleDate());

            // 查询奖金表，查询未发放的奖金明细
            List<CuMemberBonus> cuMemberBonusList = iCuMemberBonusService.queryCuMemberBonusByCondition(pkCountry, EGrantStatus.PUBLISHED.getValue(), cuMemberSettlePeriod.getStartPeriod(), cuMemberSettlePeriod.getEndPeriod());
            if (cuMemberBonusList.size() > 0) {
                // 新增交易流水
                List<CuMemberTrade> cuMemberTradeList = new ArrayList<>();
                cuMemberBonusList.forEach(cuMemberBonus -> {
                    // 奖金币（首购+复购+云代+海粉+嗨粉+店铺）
                    packAccountTrade(cuMemberTradeList, bdAccountValueMap, EAccount.BONUS.getValue(), currentDateTime, cuMemberBonus, cuMemberBonus.getRealIncomeTotal(), settleDateStr);
                });
                List<Long> seqList = iCuMemberTradeService.batchQueryCuMemberTradeSeq(cuMemberTradeList.size());
                // 新增流水明细,记录奖金明细的发放状态、消费明细
                List<CuMemberTradeDetail> cuMemberTradeDetailList = new ArrayList<>();
                Map<Integer, BdAccount> bdAccountMap = iAccountServiceApi.getAccountListByCountry(pkCountry).getData();
                for (int i = 0; i < cuMemberTradeList.size(); i++) {
                    CuMemberTrade cuMemberTrade = cuMemberTradeList.get(i);
                    cuMemberTrade.setPkId(seqList.get(i));
                    if (bdAccountMap.containsKey(cuMemberTrade.getPkAccount()) && EAccount.BONUS.getValue() == bdAccountMap.get(cuMemberTrade.getPkAccount()).getFieldValue()) {
                        // 验证有奖金币的记录发放记录
                        CuMemberTradeDetail cuMemberTradeDetail = CuMemberTradeDetail.builder()
                                .period(cuMemberSettlePeriod.getPkId())
                                .pkMemberTrade(cuMemberTrade.getPkId())
                                .grantMoney(cuMemberTrade.getTradeAmount())
                                .consumeMoney(cuMemberTrade.getTradeAmount())
                                .build();
                        cuMemberTradeDetail.setPkCountry(cuMemberTrade.getPkCountry());
                        cuMemberTradeDetail.setPkCreator(cuMemberTrade.getPkCreator());
                        cuMemberTradeDetail.setCreationTime(cuMemberTrade.getCreationTime());
                        cuMemberTradeDetailList.add(cuMemberTradeDetail);
                    }
                }
                // 批量保存交易流水，交易流水明细
                iCuMemberTradeService.batchInsertCuMemberTrade(cuMemberTradeList);
                iCuMemberTradeDetailService.batchInsertCuMemberTradeDetail(cuMemberTradeDetailList);
                // 批量更新会员账户，更新余额
                iCuMemberAccountService.updateMemberAccountGrantByPeriod(pkCountry, cuMemberSettlePeriod.getStartPeriod(), cuMemberSettlePeriod.getEndPeriod());
                // 更新奖金表发放状态
                iCuMemberBonusService.updateCuMemberBonusStatus(pkCountry, EGrantStatus.GRANT.getValue(), EGrantStatus.PUBLISHED.getValue(),
                        cuMemberSettlePeriod.getStartPeriod(), cuMemberSettlePeriod.getEndPeriod());
            }
            // 更新期间表状态
            cuMemberSettlePeriod.setIsGrant(EYesNo.YES.getIntValue());
            cuMemberSettlePeriod.setGrantDate(DateUtils.currentDateTime());
            iCuMemberSettlePeriodService.updateCuMemberSettlePeriodByDate(cuMemberSettlePeriod);
        }
        return Boolean.TRUE;
    }

    @Override
    public void grantBonusByTempPeriod(Integer pkCountry, String settleDate) {
        // 奖金发放
        CuMemberSettlePeriodExt cuMemberSettlePeriod = getCuMemberSettlePeriod(pkCountry, settleDate);
        // 查询奖金表，查询未发放的奖金明细
        List<CuMemberBonus> cuMemberBonusList = iCuMemberBonusService.queryCuMemberBonusByCondition(pkCountry, EGrantStatus.PUBLISHED.getValue(), cuMemberSettlePeriod.getStartPeriod(), cuMemberSettlePeriod.getEndPeriod());

        Map<Integer, BdAccount> bdAccountValueMap = iAccountServiceApi.getAccountMapByCountry(pkCountry).getData();
        Date currentDateTime = DateUtils.currentDateTime();
        CurrencyDTO currencyDTO = iCurrencyServiceApi.getCurrency(pkCountry).getData();
        if (cuMemberBonusList.size() > 0) {
            // 新增交易流水
            List<CuMemberTrade> cuMemberTradeList = new ArrayList<>();
            cuMemberBonusList.forEach(cuMemberBonus -> {
                // 奖金币（首购+复购+云代+海粉+嗨粉+店铺）
                packAccountTrade(cuMemberTradeList, bdAccountValueMap, EAccount.BONUS.getValue(), currentDateTime, cuMemberBonus, ComputeUtil.computeMultiply(cuMemberBonus.getRealIncomeTotal(), currencyDTO.getOutExchangeRate()), settleDate);
            });
            List<Long> seqList = iCuMemberTradeService.batchQueryCuMemberTradeSeq(cuMemberTradeList.size());
            // 新增流水明细,记录奖金明细的发放状态、消费明细
            List<CuMemberTradeDetail> cuMemberTradeDetailList = new ArrayList<>();
            Map<Integer, BdAccount> bdAccountMap = iAccountServiceApi.getAccountListByCountry(pkCountry).getData();
            for (int i = 0; i < cuMemberTradeList.size(); i++) {
                CuMemberTrade cuMemberTrade = cuMemberTradeList.get(i);
                cuMemberTrade.setPkId(seqList.get(i));
                if (bdAccountMap.containsKey(cuMemberTrade.getPkAccount()) && EAccount.BONUS.getValue() == bdAccountMap.get(cuMemberTrade.getPkAccount()).getFieldValue()) {
                    // 验证有奖金币的记录发放记录
                    CuMemberTradeDetail cuMemberTradeDetail = CuMemberTradeDetail.builder()
                            .period(cuMemberSettlePeriod.getPkId())
                            .pkMemberTrade(cuMemberTrade.getPkId())
                            .grantMoney(cuMemberTrade.getTradeAmount())
                            .consumeMoney(cuMemberTrade.getTradeAmount())
                            .build();
                    cuMemberTradeDetail.setPkCountry(cuMemberTrade.getPkCountry());
                    cuMemberTradeDetail.setPkCreator(cuMemberTrade.getPkCreator());
                    cuMemberTradeDetail.setCreationTime(cuMemberTrade.getCreationTime());
                    cuMemberTradeDetailList.add(cuMemberTradeDetail);
                }
            }
            // 批量保存交易流水，交易流水明细
            iCuMemberTradeService.batchInsertCuMemberTrade(cuMemberTradeList);
            iCuMemberTradeDetailService.batchInsertCuMemberTradeDetail(cuMemberTradeDetailList);
            // 批量更新会员账户，更新余额
            iCuMemberAccountService.updateMemberAccountGrantByPeriod(pkCountry, cuMemberSettlePeriod.getStartPeriod(), cuMemberSettlePeriod.getEndPeriod());
            // 更新奖金表发放状态
            iCuMemberBonusService.updateCuMemberBonusStatus(pkCountry, EGrantStatus.GRANT.getValue(), EGrantStatus.PUBLISHED.getValue(),
                    cuMemberSettlePeriod.getStartPeriod(), cuMemberSettlePeriod.getEndPeriod());
        }
    }

    private void packAccountTrade(List<CuMemberTrade> cuMemberTradeList, Map<Integer, BdAccount> bdAccountMap, int accountValue, Date currentDateTime,
                                  CuMemberBonus cuMemberBonus, BigDecimal grantValue, String settleDate) {
        if (ComputeUtil.compareValue(grantValue) && bdAccountMap.containsKey(accountValue)) {
            cuMemberTradeList.add(packageMemberTrade(cuMemberBonus, bdAccountMap.get(accountValue).getPkId(), grantValue, currentDateTime, settleDate));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void withdrawalBonusByPeriod(Integer pkCountry, String settleDate, String endSettleDate) {
        // 奖金可提现
        List<CuMemberSettlePeriodExt> cuMemberSettlePeriodList = getCuMemberSettlePeriod(pkCountry, settleDate, endSettleDate);

        for (CuMemberSettlePeriodExt cuMemberSettlePeriod : cuMemberSettlePeriodList) {
            if (EYesNo.YES.getIntValue() == cuMemberSettlePeriod.getIsWithdrawal()) {
                // 已经提现，则跳过
                continue;
            }
            // 批量更新会员账户，更新余额（cu_member_account)
            iCuMemberAccountService.updateMemberAccountWithdrawalByPeriod(cuMemberSettlePeriod.getStartPeriod(), cuMemberSettlePeriod.getEndPeriod(), pkCountry);
            // 更新交易明细表状态（cu_member_trade_detail）
            iCuMemberTradeDetailService.updateCuMemberTradeDetailByPeriod(cuMemberSettlePeriod.getStartPeriod(), cuMemberSettlePeriod.getEndPeriod(), pkCountry);
            // 更新奖金表发放状态（cu_member_bonus）
            iCuMemberBonusService.updateCuMemberBonusStatus(pkCountry, EGrantStatus.WITHDRAWAL.getValue(), EGrantStatus.GRANT.getValue(), cuMemberSettlePeriod.getStartPeriod(), cuMemberSettlePeriod.getEndPeriod());
            // 更新期间表状态（cu_member_settle_period_detail）
            cuMemberSettlePeriod.setIsWithdrawal(EYesNo.YES.getIntValue());
            cuMemberSettlePeriod.setWithdrawalDate(DateUtils.currentDateTime());
            iCuMemberSettlePeriodService.updateCuMemberSettlePeriodByDate(cuMemberSettlePeriod);
        }

    }

    /**
     * 封装会员 消费的 交易流水
     *
     * @param cuMemberBonus 订单主表
     * @param pkAccount     账户类型
     * @param tradeMoney    交易金额
     * @return CuMemberTrade
     */
    private CuMemberTrade packageMemberTrade(CuMemberBonus cuMemberBonus, Integer pkAccount, BigDecimal tradeMoney, Date currentDateTime, String settleDate) {
        CuMemberTrade cuMemberTrade = CuMemberTrade.builder().tradeCode(memberToolsHandler.createTradeCode(EOrderPrefix.TRADE_CODE.getValue()))
                .tradeClassify(ETradeClassify.INCOME.getValue())
                .pkMember(cuMemberBonus.getPkMember())
                .pkAccount(pkAccount)
                .pkRate(cuMemberBonus.getPkRate())
                .tradeAmount(tradeMoney)
                .sourceCode("")
                .tradeStatue(ETradeStatus.TAKE_EFFECT.getValue())
                .build();
        cuMemberTrade.setRemarks(settleDate + ETradeType.INCOME_GRANT.getLabel());
        cuMemberTrade.setTradeType(ETradeType.INCOME_GRANT.getValue());
        cuMemberTrade.setPkCountry(cuMemberBonus.getPkCountry());
        cuMemberTrade.setPkCreator(MagicNumberConstants.PK_ADMIN);
        cuMemberTrade.setCreationTime(currentDateTime);
        return cuMemberTrade;
    }
}
