package com.sckw.payment.dubbo;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sckw.core.exception.BusinessException;
import com.sckw.core.utils.DateTimeUtil;
import com.sckw.core.utils.OrderUtils;
import com.sckw.core.web.constant.HttpStatus;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.BaseResult;
import com.sckw.core.web.response.HttpResult;
import com.sckw.payment.api.dubbo.PaymentDubboService;
import com.sckw.payment.api.model.WalletFreeze;
import com.sckw.payment.api.model.constant.ChannelEnum;
import com.sckw.payment.api.model.constant.OrderEnum;
import com.sckw.payment.api.model.dto.LedgerCount;
import com.sckw.payment.api.model.dto.SettlementMoney;
import com.sckw.payment.dao.KwpBizWalletMapper;
import com.sckw.payment.dao.KwpBizWalletPrepayMapper;
import com.sckw.payment.model.KwpBizWallet;
import com.sckw.payment.model.KwpBizWalletPrepay;
import com.sckw.payment.model.constant.LogisticsUnitType;
import com.sckw.payment.model.constant.TradeUnitType;
import com.sckw.payment.model.dto.LedgerSize;
import com.sckw.payment.model.dto.MoneyType;
import com.sckw.payment.service.*;
import com.sckw.payment.utils.DecimalUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xucaiqin
 * @date 2023-08-18 17:26:05
 */
@Service
@DubboService(group = "design", version = "1.0.0")
@RequiredArgsConstructor
@Slf4j
public class PaymentDubboServiceImpl implements PaymentDubboService {
    private final KwpLedgerLogisticsService ledgerLogisticsService;
    private final KwpLedgerTradeService kwpLedgerTradeService;
    private final KwpSettlementLogisticsService kwpSettlementLogisticsService;
    private final KwpSettlementTradeService kwpSettlementTradeService;
    private final WalletService walletService;
    private final KwpTradeFreezeService kwpTradeFreezeService;
    private final KwpBizWalletPrepayMapper kwpBizWalletPrepayMapper;
    private final KwpBizWalletMapper kwpBizWalletMapper;


    private SettlementMoney change(List<MoneyType> moneyType) {
        DecimalFormat df = new DecimalFormat("0.00");
        BigDecimal curMoney = new BigDecimal("0.0"), preMoney = new BigDecimal("0.0");
        for (MoneyType type : moneyType) {
            if (type.type() == 1) {
                curMoney = type.money();
            } else {
                preMoney = type.money();
            }
        }
        int flag = curMoney.compareTo(preMoney) > 0 ? 1 : 2;

        String percent = DecimalUtils.percent(curMoney.subtract(preMoney), preMoney);
        return new SettlementMoney(df.format(curMoney), df.format(preMoney), percent, flag);
    }

    @Override
    public HttpResult freezeMoney(Long payEntId, ChannelEnum channel, Long receiveEntId, BigDecimal money, Long tOrderId) {
        log.info("贸易下单冻结订单，payEntId：{} channel：{} receiveEntId：{} money：{} tOrderId：{}", payEntId, channel, receiveEntId, money, tOrderId);
        if (Objects.isNull(payEntId)) {
            return HttpResult.error("支付企业不能为空");
        }
        if (Objects.isNull(channel)) {
            return HttpResult.error("支付渠道不能为空");
        }
        if (Objects.isNull(receiveEntId)) {
            return HttpResult.error("收款企业不能为空");
        }
        if (Objects.isNull(money)) {
            return HttpResult.error("订单金额不能为空");
        }
        if (Objects.isNull(tOrderId)) {
            return HttpResult.error("贸易订单id不能为空");
        }
        long m;
        try {
            m = money.multiply(new BigDecimal("100")).longValueExact();
        } catch (Exception e) {
            log.error("金额转换异常：{}", e.getMessage(), e);
            return HttpResult.error("金额异常");
        }
        //settlementTradeFreeze冻结订单编号规则
        String orderNo = OrderUtils.generateOrderNo("STF");
        HttpResult httpResult = walletService.freezeMoney(payEntId, channel, receiveEntId, m, orderNo);
        //记录订单流水号
        if (httpResult.getCode() == HttpStatus.SUCCESS_CODE) {
            kwpTradeFreezeService.save(tOrderId, orderNo);
        }
        log.info("贸易下单冻结订单:{}", JSONObject.toJSONString(httpResult));
        return httpResult;
    }

    @Override
    public Map<OrderEnum, List<String>> checkLedger(Long entId, Long entTarget) {
        if (Objects.isNull(entId) || Objects.isNull(entTarget)) {
            throw new BusinessException("企业id不能为空");
        }
        List<String> logistics = ledgerLogisticsService.checkOrder(entId, entTarget);
        List<String> trade = kwpLedgerTradeService.checkOrder(entId, entTarget);
        Map<OrderEnum, List<String>> res = new HashMap<>(2);
        res.put(OrderEnum.LOGISTICS, logistics);
        res.put(OrderEnum.TRADE, trade);
        return res;
    }

    @Override
    public Map<OrderEnum, List<String>> checkSettlement(Long entId, Long entTarget) {
        if (Objects.isNull(entId) || Objects.isNull(entTarget)) {
            throw new BusinessException("企业id不能为空");
        }
        List<String> logistics = kwpSettlementLogisticsService.checkOrder(entId, entTarget);
        List<String> trade = kwpSettlementTradeService.checkOrder(entId, entTarget);
        Map<OrderEnum, List<String>> res = new HashMap<>(2);
        res.put(OrderEnum.LOGISTICS, logistics);
        res.put(OrderEnum.TRADE, trade);
        return res;
    }

    @Override
    public LedgerCount countLedger(Long entId, List<Long> enterpriseIds) {
        enterpriseIds = enterpriseIds.stream().distinct().collect(Collectors.toList());
        LedgerSize count = ledgerLogisticsService.count(entId, enterpriseIds);
        LedgerSize ledgerSize = kwpLedgerTradeService.count(entId, enterpriseIds);
        return new LedgerCount(ledgerSize.send(), ledgerSize.receive(), count.send(), count.receive());
    }


    @Override
    public SettlementMoney countSell(Long entId, Integer countType) {
        log.info("销售统计：{} {}", entId, countType);
        if (Objects.isNull(countType)) {
            return new SettlementMoney("0.00", "0.00", "0.00%", 1);
        }
        List<LocalDateTime> cur = new ArrayList<>();
        List<LocalDateTime> pre = new ArrayList<>();
        //按周统计
        if (countType == 2) {
            cur.add(DateTimeUtil.getComputeDaysStart(-6));
            cur.add(DateTimeUtil.getComputeDaysEnd(0));
            pre.add(DateTimeUtil.getComputeDaysStart(-13));
            pre.add(DateTimeUtil.getComputeDaysEnd(-7));
        } else if (countType == 3) {
            cur.add(DateTimeUtil.getComputeMonthStart(-1, 1));
            cur.add(DateTimeUtil.getComputeMonthEnd(0, 0));
            pre.add(DateTimeUtil.getComputeMonthStart(-2, 1));
            pre.add(DateTimeUtil.getComputeMonthEnd(-1, 0));
        }
        List<MoneyType> moneyType = kwpSettlementTradeService.moneySum(entId, cur, pre, TradeUnitType.SELL);
        return change(moneyType);
    }

    @Override
    public SettlementMoney countPurchase(Long entId, Integer countType) {
        log.info("采购统计：{} {}", entId, countType);
        if (Objects.isNull(countType)) {
            return new SettlementMoney("0.00", "0.00", "0.00%", 1);
        }
        List<LocalDateTime> cur = new ArrayList<>();
        List<LocalDateTime> pre = new ArrayList<>();
        //按周统计
        if (countType == 2) {
            cur.add(DateTimeUtil.getComputeDaysStart(-6));
            cur.add(DateTimeUtil.getComputeDaysEnd(0));
            pre.add(DateTimeUtil.getComputeDaysStart(-13));
            pre.add(DateTimeUtil.getComputeDaysEnd(-7));
        } else if (countType == 3) {
            cur.add(DateTimeUtil.getComputeMonthStart(-1, 1));
            cur.add(DateTimeUtil.getComputeMonthEnd(0, 0));
            pre.add(DateTimeUtil.getComputeMonthStart(-2, 1));
            pre.add(DateTimeUtil.getComputeMonthEnd(-1, 0));
        }
        List<MoneyType> moneyType = kwpSettlementTradeService.moneySum(entId, cur, pre, TradeUnitType.PURCHASE);
        return change(moneyType);
    }


    @Override
    public SettlementMoney countCarrier(Long entId, Integer countType) {
        log.info("承运统计：{} {}", entId, countType);
        if (Objects.isNull(countType)) {
            return new SettlementMoney("0.00", "0.00", "0.00%", 1);
        }
        List<LocalDateTime> cur = new ArrayList<>();
        List<LocalDateTime> pre = new ArrayList<>();
        //按周统计
        if (countType == 2) {
            cur.add(DateTimeUtil.getComputeDaysStart(-6));
            cur.add(DateTimeUtil.getComputeDaysEnd(0));
            pre.add(DateTimeUtil.getComputeDaysStart(-13));
            pre.add(DateTimeUtil.getComputeDaysEnd(-7));
        } else if (countType == 3) {
            cur.add(DateTimeUtil.getComputeMonthStart(-1, 1));
            cur.add(DateTimeUtil.getComputeMonthEnd(0, 0));
            pre.add(DateTimeUtil.getComputeMonthStart(-2, 1));
            pre.add(DateTimeUtil.getComputeMonthEnd(-1, 0));
        }
        List<MoneyType> moneyType = kwpSettlementLogisticsService.moneySum(entId, cur, pre, LogisticsUnitType.CARRIER);
        return change(moneyType);

    }

    @Override
    public SettlementMoney countShipper(Long entId, Integer countType) {
        log.info("托运统计：{} {}", entId, countType);
        if (Objects.isNull(countType)) {
            return new SettlementMoney("0.00", "0.00", "0.00%", 1);
        }
        List<LocalDateTime> cur = new ArrayList<>();
        List<LocalDateTime> pre = new ArrayList<>();
        //按周统计
        if (countType == 2) {
            cur.add(DateTimeUtil.getComputeDaysStart(-6));
            cur.add(DateTimeUtil.getComputeDaysEnd(0));
            pre.add(DateTimeUtil.getComputeDaysStart(-13));
            pre.add(DateTimeUtil.getComputeDaysEnd(-7));
        } else if (countType == 3) {
            cur.add(DateTimeUtil.getComputeMonthStart(-1, 1));
            cur.add(DateTimeUtil.getComputeMonthEnd(0, 0));
            pre.add(DateTimeUtil.getComputeMonthStart(-2, 1));
            pre.add(DateTimeUtil.getComputeMonthEnd(-1, 0));
        }
        List<MoneyType> moneyType = kwpSettlementLogisticsService.moneySum(entId, cur, pre, LogisticsUnitType.SHIPPER);
        return change(moneyType);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResult<Boolean> freezeMoney(WalletFreeze walletFreeze) {
        log.info("冻结钱包：{}", JSONObject.toJSONString(walletFreeze));
        KwpBizWallet one = kwpBizWalletMapper.selectOne(new LambdaQueryWrapper<KwpBizWallet>()
                .eq(KwpBizWallet::getSupEntId, walletFreeze.getSaleEntId())
                .eq(KwpBizWallet::getProEntId, walletFreeze.getBuyEntId()).eq(KwpBizWallet::getState, 1)
        );
        if (Objects.isNull(one)) {
            return BaseResult.failed("钱包不存在,请核实");
        }
        BigDecimal amount = one.getAmount();
        if (NumberUtil.isLess(amount, walletFreeze.getMoney())) {
            return BaseResult.failed("可用余额不足");
        }
        one.setAmount(NumberUtil.sub(amount, walletFreeze.getMoney()));
        one.setPrepayAmount(NumberUtil.add(one.getPrepayAmount(), walletFreeze.getMoney()));
        one.setUpdateUser(LoginUserHolder.getUserName());
        kwpBizWalletMapper.updateById(one);
        //新增订单
        KwpBizWalletPrepay kwpBizWalletPrepay = new KwpBizWalletPrepay();
        kwpBizWalletPrepay.setWalletId(one.getId());
        kwpBizWalletPrepay.setOrderId(walletFreeze.getTTradeOrderId());
        kwpBizWalletPrepay.setChangeAmount(walletFreeze.getMoney());
        kwpBizWalletPrepay.setAmount(one.getAmount());
        kwpBizWalletPrepay.setPrepayAmount(one.getPrepayAmount());
        kwpBizWalletPrepay.setType(2);
        kwpBizWalletPrepay.setRemark(StrUtil.format("[订单号：{}]冻结", walletFreeze.getOrderNo()));
        kwpBizWalletPrepay.setVoucherUrl("");
        kwpBizWalletPrepay.setCreateTime(new Date());
        kwpBizWalletPrepay.setUpdateTime(new Date());
        kwpBizWalletPrepay.setCreateUser(LoginUserHolder.getUserName());
        kwpBizWalletPrepay.setUpdateUser(LoginUserHolder.getUserName());

        kwpBizWalletPrepayMapper.insert(kwpBizWalletPrepay);
        return BaseResult.success();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResult<Boolean> dealMoney(WalletFreeze walletFreeze) {
        log.info("钱包结算 {}", JSONObject.toJSONString(walletFreeze));
        Long tTradeOrderId = walletFreeze.getTTradeOrderId();
        KwpBizWalletPrepay one = kwpBizWalletPrepayMapper.selectOne(new LambdaQueryWrapper<KwpBizWalletPrepay>()
                .eq(KwpBizWalletPrepay::getOrderId, tTradeOrderId)
                .eq(KwpBizWalletPrepay::getType, 2)
                .last("limit 1")
        );
        if (Objects.isNull(one)) {
            return BaseResult.failed("冻结订单不存在");
        }

        KwpBizWallet wallet = kwpBizWalletMapper.selectById(one.getWalletId());
        if (Objects.isNull(wallet) || Objects.equals(wallet.getState(), 0)) {
            return BaseResult.failed("钱包不存在或状态异常");
        }
        BigDecimal changeAmount = one.getChangeAmount();//冻结金额
        //钱包实际可用
        BigDecimal amount = wallet.getAmount();
        //新增解冻订单
        amount = NumberUtil.add(amount, changeAmount);
        KwpBizWalletPrepay kwpBizWalletPrepay = new KwpBizWalletPrepay();
        kwpBizWalletPrepay.setWalletId(wallet.getId());
        kwpBizWalletPrepay.setOrderId(walletFreeze.getTTradeOrderId());
        kwpBizWalletPrepay.setChangeAmount(changeAmount);
        kwpBizWalletPrepay.setAmount(amount);
        kwpBizWalletPrepay.setPrepayAmount(NumberUtil.sub(wallet.getPrepayAmount(), changeAmount));
        kwpBizWalletPrepay.setType(3);
        kwpBizWalletPrepay.setRemark(StrUtil.format("[{}][结算]解冻订单总金额", walletFreeze.getOrderNo()));
        kwpBizWalletPrepay.setVoucherUrl("");
        kwpBizWalletPrepay.setCreateTime(new Date());
        kwpBizWalletPrepay.setUpdateTime(new Date());
        kwpBizWalletPrepay.setCreateUser(LoginUserHolder.getUserName());
        kwpBizWalletPrepay.setUpdateUser(LoginUserHolder.getUserName());
        kwpBizWalletPrepayMapper.insert(kwpBizWalletPrepay);

        //新增消费订单
        KwpBizWalletPrepay kwpBizWalletPrepay2 = new KwpBizWalletPrepay();
        kwpBizWalletPrepay2.setWalletId(wallet.getId());
        kwpBizWalletPrepay2.setOrderId(walletFreeze.getTTradeOrderId());
        kwpBizWalletPrepay2.setChangeAmount(walletFreeze.getMoney());
        kwpBizWalletPrepay2.setAmount(NumberUtil.sub(amount, walletFreeze.getMoney()));
        kwpBizWalletPrepay2.setPrepayAmount(kwpBizWalletPrepay.getPrepayAmount());
        kwpBizWalletPrepay2.setType(4);
        kwpBizWalletPrepay2.setRemark(StrUtil.format("[{}][结算]扣除订单总金额", walletFreeze.getOrderNo()));
        kwpBizWalletPrepay2.setVoucherUrl("");
        kwpBizWalletPrepay2.setCreateTime(new Date());
        kwpBizWalletPrepay2.setUpdateTime(new Date());
        kwpBizWalletPrepay2.setCreateUser(LoginUserHolder.getUserName());
        kwpBizWalletPrepay2.setUpdateUser(LoginUserHolder.getUserName());
        kwpBizWalletPrepayMapper.insert(kwpBizWalletPrepay2);

        wallet.setAmount(kwpBizWalletPrepay2.getAmount());
        wallet.setPrepayAmount(kwpBizWalletPrepay2.getPrepayAmount());
        kwpBizWalletMapper.updateById(wallet);
        return BaseResult.success();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResult<Boolean> unfreezeMoney(WalletFreeze walletFreeze) {
        log.info("解冻钱包：{}", JSONObject.toJSONString(walletFreeze));
        Long tTradeOrderId = walletFreeze.getTTradeOrderId();
        KwpBizWalletPrepay one = kwpBizWalletPrepayMapper.selectOne(new LambdaQueryWrapper<KwpBizWalletPrepay>()
                .eq(KwpBizWalletPrepay::getOrderId, tTradeOrderId)
                .eq(KwpBizWalletPrepay::getType, 2)
                .last("limit 1")
        );
        if (Objects.isNull(one)) {
            return BaseResult.failed("冻结订单不存在");
        }

        KwpBizWallet wallet = kwpBizWalletMapper.selectById(one.getWalletId());
        if (Objects.isNull(wallet) || Objects.equals(wallet.getState(), 0)) {
            return BaseResult.failed("钱包不存在或状态异常");
        }
        BigDecimal changeAmount = one.getChangeAmount();//冻结金额
        //钱包实际可用
        BigDecimal amount = wallet.getAmount();
        //新增解冻订单
        amount = NumberUtil.add(amount, changeAmount);
        KwpBizWalletPrepay kwpBizWalletPrepay = new KwpBizWalletPrepay();
        kwpBizWalletPrepay.setWalletId(wallet.getId());
        kwpBizWalletPrepay.setOrderId(walletFreeze.getTTradeOrderId());
        kwpBizWalletPrepay.setChangeAmount(changeAmount);
        kwpBizWalletPrepay.setAmount(amount);
        kwpBizWalletPrepay.setPrepayAmount(NumberUtil.sub(wallet.getPrepayAmount(), changeAmount));
        kwpBizWalletPrepay.setType(3);
        kwpBizWalletPrepay.setRemark(StrUtil.format("[订单号：{}]解冻", walletFreeze.getOrderNo()));
        kwpBizWalletPrepay.setVoucherUrl("");
        kwpBizWalletPrepay.setCreateTime(new Date());
        kwpBizWalletPrepay.setUpdateTime(new Date());
        kwpBizWalletPrepay.setCreateUser(LoginUserHolder.getUserName());
        kwpBizWalletPrepay.setUpdateUser(LoginUserHolder.getUserName());
        kwpBizWalletPrepayMapper.insert(kwpBizWalletPrepay);


        wallet.setAmount(amount);
        wallet.setPrepayAmount(kwpBizWalletPrepay.getPrepayAmount());
        kwpBizWalletMapper.updateById(wallet);
        return BaseResult.success();
    }
}

