package com.bonus.canteen.core.account.v3.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.common.houqin.constant.LeConstants;
import com.bonus.canteen.core.account.v3.api.dto.AccRechargeSumApiDTO;
import com.bonus.canteen.core.account.v3.api.vo.AccRechargeSumApiVO;
import com.bonus.canteen.core.account.v3.app.dto.AppTradeDetailListDTO;
import com.bonus.canteen.core.account.v3.app.vo.AppAccTradePageVO;
import com.bonus.canteen.core.account.v3.constants.AccTradeStateEnum;
import com.bonus.canteen.core.account.v3.custom.AccRechargeCustomBusiness;
import com.bonus.canteen.core.account.v3.mapper.AccTradeMapper;
import com.bonus.canteen.core.account.v3.model.AccTrade;
import com.bonus.canteen.core.account.v3.model.AccTradeWalletDetail;
import com.bonus.canteen.core.account.v3.mq.send.model.RepAccMqModel;
import com.bonus.canteen.core.account.v3.po.AccTradeAddPO;
import com.bonus.canteen.core.account.v3.po.AccTradeWalletPO;
import com.bonus.canteen.core.account.v3.po.AccWalletPayPO;
import com.bonus.canteen.core.account.v3.service.AccTradeService;
import com.bonus.canteen.core.account.v3.service.AccTradeWalletDetailService;
import com.bonus.canteen.core.account.v3.service.AccWalletInfoService;
import com.bonus.canteen.core.account.v3.web.vo.AccInfoVO;
import com.bonus.canteen.core.account.v3.web.vo.AccWalletInfoVO;
import com.bonus.canteen.core.customer.api.CustInfoApi;
import com.bonus.canteen.core.customer.model.CustInfo;
import com.bonus.canteen.core.pay.common.constants.PayChannelEnum;
import com.bonus.canteen.core.pay.common.constants.PayTypeEnum;
import com.bonus.common.houqin.utils.id.Id;
import com.github.pagehelper.page.PageMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class AccTradeServiceImpl extends ServiceImpl<AccTradeMapper, AccTrade> implements AccTradeService {
   private static final Logger log = LoggerFactory.getLogger(AccTradeServiceImpl.class);

    @Resource
    @Lazy
    private AccRechargeCustomBusiness accRechargeCustomBusiness;
    @Resource
    @Lazy
    private AccTradeWalletDetailService accTradeWalletDetailService;
    @Resource
    @Lazy
    private AccWalletInfoService accWalletInfoService;
    @Resource
    @Lazy
    private CustInfoApi custInfoApi;

   @Override
   public Page<AppAccTradePageVO> queryTradeAppPage(AppTradeDetailListDTO dto) {
       Page<AccTrade> page = new Page(dto.getCurrent(), dto.getSize());
       Page<AppAccTradePageVO> pages = ((AccTradeMapper) this.baseMapper).queryTradeAppPage(page,dto);
       pages.setTotal(((AccTradeMapper) this.baseMapper).queryTradeAppPage(page, dto).getTotal());
       return pages;
   }
    @Override
    public Long insertAccTradeAndDetail(AccInfoVO accInfoVO, Integer tradeType, BigDecimal amount, String mchSn, List<AccWalletPayPO> walletPayList, Long orderNo, String remark, Integer payState, boolean updateWalletInfo) {
       return this.insertAccTradeAndDetail(accInfoVO, tradeType, amount, mchSn, walletPayList, orderNo, remark,
               payState, updateWalletInfo, SecurityUtils.getUsername());
    }
    public Long insertAccTradeAndDetail(AccInfoVO accInfoVO, Integer tradeType, BigDecimal amount, String mchSn, List<AccWalletPayPO> walletPayList, Long orderNo, String remark, Integer payState, boolean updateWalletInfo, String userName) {
        LocalDateTime now = LocalDateTime.now();
        AccTradeAddPO accTradeAddPO = AccTradeAddPO.builder().tradeTime(now).custId(accInfoVO.getCustId()).actualAmount(amount).amount(amount).tradeType(tradeType).payChannel(PayChannelEnum.ACC.getKey()).payType(PayTypeEnum.MEAL_CARD.getKey()).payState(payState).tradeState(AccTradeStateEnum.TAKE_EFFECT.getKey()).machineSn(mchSn).remark(remark).leOrdNo(orderNo).crby(userName).build();
        if (BooleanUtil.isFalse(updateWalletInfo)) {
            accTradeAddPO.setWalletBalTotal(accInfoVO.getAccBalTotal());
            accTradeAddPO.setAccAllBal(accInfoVO.getAccAllBal());
        } else {
            accTradeAddPO.setWalletBalTotal(accInfoVO.getAccBalTotal().subtract(amount));
            accTradeAddPO.setAccAllBal(accInfoVO.getAccAllBal().subtract(amount));
        }

        Long tradeId = this.insertAccTrade(accTradeAddPO);
        Map<Integer, AccWalletInfoVO> walletInfoMap = (Map)accInfoVO.getWalletInfoList().stream().collect(Collectors.toMap(AccWalletInfoVO::getWalletId, Function.identity()));
        Iterator var15 = walletPayList.iterator();

        while(var15.hasNext()) {
            AccWalletPayPO walletPayPO = (AccWalletPayPO)var15.next();
            if (ObjectUtil.isNotNull(walletPayPO.getAmount()) && walletPayPO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
                Integer walletId = walletPayPO.getWalletId();
                AccWalletInfoVO walletInfo = (AccWalletInfoVO)walletInfoMap.get(walletId);
                AccTradeWalletPO accTradeWalletPO = AccTradeWalletPO.builder().custId(accInfoVO.getCustId()).tradeId(tradeId).tradeType(tradeType).walletId(walletId).amount(walletPayPO.getAmount()).walletBal(walletPayPO.getWalletBal()).frozenBalance(walletInfo.getFrozenBalance()).tradeTime(now).build();
                this.accTradeWalletDetailService.insertAccTradeWalletDetail(accTradeWalletPO);
                if (updateWalletInfo) {
                    this.accWalletInfoService.updateAccWalletInfoForUse(accInfoVO.getCustId(), walletPayPO.getWalletId(), walletPayPO.getAmount());
                }
            }
        }

        return tradeId;
    }

    @Override
    public Long insertAccTrade(AccTradeAddPO addPo) {
        this.accRechargeCustomBusiness.preAddAccTradeParam(addPo);
        AccTrade accTrade = new AccTrade();
        BeanUtil.copyProperties(addPo, accTrade, new String[0]);
        long tradeId = Id.next();
        accTrade.setId(tradeId);
        if (ObjectUtil.isNull(addPo.getCustPsnOrgBoolean())) {
            CustInfo custInfo = this.custInfoApi.getCustInfoByCustId(addPo.getCustId());
            accTrade.setOrgId((Long) Optional.ofNullable(custInfo.getOrgId()).orElse(LeConstants.DATA_DEFAULT_LONG));
            accTrade.setPsnType((Integer)Optional.ofNullable(custInfo.getPsnType()).orElse(LeConstants.DATA_DEFAULT_INTEGER));
        }

        log.info("[账户交易记录]新增开始:{}", JSONUtil.toJsonStr(accTrade));
        ((AccTradeMapper)this.baseMapper).insert(accTrade);
        log.info("[账户交易记录]新增结束");
        return tradeId;
    }

    @Override
    public void updateTradeById(AccTrade updateTrade) {
        this.updateById(updateTrade);
    }

    @Override
    public List<RepAccMqModel> listAccTradeForSend(List<Long> tradeIdList) {
        return ((AccTradeMapper)this.baseMapper).listAccTradeForSend(tradeIdList);
    }

    @Override
    public void insertAccTradeForTradeId(AccTradeAddPO addPo) {
        this.accRechargeCustomBusiness.preAddAccTradeParam(addPo);
        AccTrade accTrade = new AccTrade();
        BeanUtil.copyProperties(addPo, accTrade, new String[0]);
        accTrade.setId(addPo.getTradeId());
        log.info("[账户交易记录]新增开始:{}", JSONUtil.toJsonStr(accTrade));
        ((AccTradeMapper)this.baseMapper).insert(accTrade);
        log.info("[账户交易记录]新增结束");
    }

    @Override
    public AccRechargeSumApiVO getAccRechargeSum(AccRechargeSumApiDTO accRechargeSumApiDTO) {
        return ((AccTradeMapper)this.baseMapper).getAccRechargeSum(accRechargeSumApiDTO);
    }

    @Override
    public AppAccTradePageVO getOneTradeApp(Long accTradeId) {
        return ((AccTradeMapper)this.baseMapper).getOneTradeApp(accTradeId);
    }

    public List<AccTradeWalletDetail> listAccSubsidyTrade(Long custId, List<Integer> tradeTypeList) {
        return ((AccTradeMapper)this.baseMapper).listAccSubsidyTrade(custId, tradeTypeList);
    }
}
