package com.clx.performance.service.impl.settle;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.clx.performance.component.IdGenerateSnowFlake;
import com.clx.performance.dao.settle.NetworkCaseOutRecordDao;
import com.clx.performance.dao.settle.NetworkDriverAccountDao;
import com.clx.performance.dao.settle.NetworkDriverRunningWaterRecordDao;
import com.clx.performance.enums.NetworkDriverAccountEnum;
import com.clx.performance.model.settle.NetworkCaseOutRecord;
import com.clx.performance.model.settle.NetworkDriverAccount;
import com.clx.performance.model.settle.NetworkDriverRunningWaterRecord;
import com.clx.performance.model.settle.SettlementDriverDetail;
import com.clx.performance.param.app.NetworkDriverPageParam;
import com.clx.performance.param.pc.PageNetworkAccountInfoListParam;
import com.clx.performance.service.settle.NetworkDriverRunningWaterRecordService;
import com.clx.performance.vo.app.APPNetworkDriverRunningWaterRecordVO;
import com.clx.performance.vo.pc.NetworkDriverRunningWaterRecordVO;
import com.clx.user.feign.DriverFeign;
import com.clx.user.vo.feign.BankCardVO;
import com.msl.common.base.Optional;
import com.msl.common.enums.ResultCodeEnum;
import com.msl.common.result.Result;
import com.msl.user.utils.TokenUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * @author kavin
 * Date 2023-12-19
 * Time 11:34
 */
@Service
@AllArgsConstructor
@Slf4j
public class NetworkDriverRunningWaterRecordServiceImpl implements NetworkDriverRunningWaterRecordService, InitializingBean {

    private final static Map<Integer, Consumer<SettlementDriverDetail>> strategyMap = new HashMap<>();

    private final NetworkDriverRunningWaterRecordDao networkDriverRunningWaterRecordDao;

    private final NetworkDriverAccountDao networkDriverAccountDao;

    private final IdGenerateSnowFlake idGenerateSnowFlake;

    private final DriverFeign driverFeign;

    private final NetworkCaseOutRecordDao networkCaseOutRecordDao;

    @Override
    public IPage<NetworkDriverRunningWaterRecordVO> networkDriverRunningWaterRecordList(PageNetworkAccountInfoListParam param) {
        return networkDriverRunningWaterRecordDao.networkDriverRunningWaterRecordDao(param);
    }

    /**
     * 运单同步网络货运生成司机运单结算流水
     * @param settlementDriverDetail
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateSettlementRunningWaterRecord(SettlementDriverDetail settlementDriverDetail) {
        log.info("运单同步网络货运生成司机运单结算流水");
        NetworkDriverAccount networkDriverAccount = networkDriverAccountDao.getOneByField(NetworkDriverAccount::getDriverUserNo, settlementDriverDetail.getDriverUserNo()).get();
        log.info("查询出NetworkDriverAccount{}", JSONUtil.parse(networkDriverAccount));
        NetworkDriverAccount build = NetworkDriverAccount.builder().id(networkDriverAccount.getId())
                .usableBalance(settlementDriverDetail.getSettlementFreight())
                .frozenBalance(BigDecimal.ZERO)
                .accountBalance(settlementDriverDetail.getSettlementFreight()).build();
        while (true) {
            NetworkDriverAccount account = networkDriverAccountDao.getEntityByKey(build.getId()).get();
            build.setModifiedTime(account.getModifiedTime());
            Integer i = networkDriverAccountDao.updateAccountCAS(build, LocalDateTime.now(), true);
            log.info("网络货运账户更新成功");
            if (i == 1) {
                account = networkDriverAccountDao.getEntityByKey(build.getId()).get();
                NetworkDriverRunningWaterRecord entity = NetworkDriverRunningWaterRecord.builder()
                        .mobile(networkDriverAccount.getMobile())
                        .usableBalance(account.getUsableBalance())
                        .alterationBalance(settlementDriverDetail.getSettlementFreight())
                        .accountBalance(account.getAccountBalance())
                        .frozenBalance(account.getFrozenBalance()).createBy("系统")
                        .fundType(NetworkDriverAccountEnum.FundType.INCOME.getCode())
                        .fundTypeMsg(NetworkDriverAccountEnum.FundType.INCOME.getMsg())
                        .driverUserName(account.getDriverUserName())
                        .driverUserNo(account.getDriverUserNo())
                        .runningWaterNo(idGenerateSnowFlake.nextId(2L))
                        .runningWaterTypeMsg(NetworkDriverAccountEnum.RunningWaterStatus.SETTLEMENT.getMsg())
                        .runningWaterType(NetworkDriverAccountEnum.RunningWaterStatus.SETTLEMENT.getCode())
                        .childNo(settlementDriverDetail.getChildNo())
                        .orderNo(settlementDriverDetail.getOrderNo())
                        .orderGoodsNo(settlementDriverDetail.getOrderGoodsNo())
                        .build();

                networkDriverRunningWaterRecordDao.saveEntity(entity);
                break;
            }
        }

    }

    /**
     * 运单同步网络货运后司机运单提现冻结流水
     * @param settlementDriverDetail
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateCaseOutFrozenRunningWaterRecord(SettlementDriverDetail settlementDriverDetail) {
        log.info("运单同步网络货运后司机运单提现冻结流水");
        NetworkDriverAccount networkDriverAccount = networkDriverAccountDao.getOneByField(NetworkDriverAccount::getDriverUserNo, settlementDriverDetail.getDriverUserNo()).get();
        log.info("查询出NetworkDriverAccount{}", JSONUtil.parse(networkDriverAccount));
        NetworkDriverAccount build = NetworkDriverAccount.builder().id(networkDriverAccount.getId())
                .frozenBalance(settlementDriverDetail.getSettlementFreight())
                .accountBalance(BigDecimal.ZERO)
                .usableBalance(settlementDriverDetail.getSettlementFreight()).build();
        while (true) {
            NetworkDriverAccount account = networkDriverAccountDao.getEntityByKey(build.getId()).get();
            build.setModifiedTime(account.getModifiedTime());
            Integer i = networkDriverAccountDao.updateAccountCAS(build, LocalDateTime.now(), false);
            log.info("网络货运账户更新成功");
            if (i == 1) {
                account = networkDriverAccountDao.getEntityByKey(build.getId()).get();
                NetworkDriverRunningWaterRecord entity = NetworkDriverRunningWaterRecord.builder()
                        .usableBalance(account.getUsableBalance())
                        .mobile(networkDriverAccount.getMobile())
                        .alterationBalance(settlementDriverDetail.getSettlementFreight())
                        .accountBalance(account.getAccountBalance())
                        .frozenBalance(account.getFrozenBalance()).createBy("系统")
                        .fundType(NetworkDriverAccountEnum.FundType.FROZEN.getCode())
                        .fundTypeMsg(NetworkDriverAccountEnum.FundType.FROZEN.getMsg())
                        .driverUserName(account.getDriverUserName())
                        .driverUserNo(account.getDriverUserNo())
                        .runningWaterNo(idGenerateSnowFlake.nextId(3L))
                        .runningWaterTypeMsg(NetworkDriverAccountEnum.RunningWaterStatus.CASE_OUT_FROZEN.getMsg())
                        .frozenFlag(0)
                        .runningWaterType(NetworkDriverAccountEnum.RunningWaterStatus.CASE_OUT_FROZEN.getCode())
                        .childNo(settlementDriverDetail.getChildNo())
                        .orderNo(settlementDriverDetail.getOrderNo())
                        .orderGoodsNo(settlementDriverDetail.getOrderGoodsNo())
                        .build();

                networkDriverRunningWaterRecordDao.saveEntity(entity);
                break;
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateCaseOutSuccessRunningWaterRecord(SettlementDriverDetail settlementDriverDetail) {
        log.info("运单同步网络货运生成司机运单提现成功流水");
        NetworkDriverAccount networkDriverAccount = networkDriverAccountDao.getOneByField(NetworkDriverAccount::getDriverUserNo, settlementDriverDetail.getDriverUserNo()).get();
        log.info("查询出NetworkDriverAccount{}", JSONUtil.parse(networkDriverAccount));
        NetworkDriverAccount build = NetworkDriverAccount.builder().id(networkDriverAccount.getId())
                .frozenBalance(settlementDriverDetail.getSettlementFreight().negate())
                .usableBalance(BigDecimal.ZERO)
                .accountBalance(settlementDriverDetail.getSettlementFreight()).build();
        while (true) {
            NetworkDriverAccount account = networkDriverAccountDao.getEntityByKey(build.getId()).get();
            build.setModifiedTime(account.getModifiedTime());
            Integer i = networkDriverAccountDao.updateAccountCAS(build, LocalDateTime.now(), false);
            if (i == 1) {
                networkDriverRunningWaterRecordDao.updateFrozenFlagByChildNo(settlementDriverDetail.getChildNo());


                account = networkDriverAccountDao.getEntityByKey(build.getId()).get();
                NetworkDriverRunningWaterRecord entity = NetworkDriverRunningWaterRecord.builder()
                        .usableBalance(account.getUsableBalance())
                        .mobile(networkDriverAccount.getMobile())
                        .alterationBalance(settlementDriverDetail.getSettlementFreight())
                        .accountBalance(account.getAccountBalance())
                        .frozenBalance(account.getFrozenBalance()).createBy("系统")
                        .fundType(NetworkDriverAccountEnum.FundType.EXPENDITURE.getCode())
                        .fundTypeMsg(NetworkDriverAccountEnum.FundType.EXPENDITURE.getMsg())
                        .driverUserName(account.getDriverUserName())
                        .driverUserNo(account.getDriverUserNo())
                        .runningWaterNo(idGenerateSnowFlake.nextId(3L))
                        .runningWaterTypeMsg(NetworkDriverAccountEnum.RunningWaterStatus.CASE_OUT_SUCCESS.getMsg())
                        .runningWaterType(NetworkDriverAccountEnum.RunningWaterStatus.CASE_OUT_SUCCESS.getCode())
                        .childNo(settlementDriverDetail.getChildNo())
                        .orderNo(settlementDriverDetail.getOrderNo())
                        .orderGoodsNo(settlementDriverDetail.getOrderGoodsNo())
                        .build();

                networkDriverRunningWaterRecordDao.saveEntity(entity);
                break;
            }
        }
    }

    @Override
    public void generateNetworkDriverRunningWaterRecord(SettlementDriverDetail settlementDriverDetail, Integer runningWaterType) {
        if (NetworkDriverAccountEnum.RunningWaterStatus.SETTLEMENT.getCode().equals(runningWaterType)) {
            log.info("执行生成网络货运钱包相关，参数userNo:{},money{},runningWaterType:{}", settlementDriverDetail.getDriverUserNo(), settlementDriverDetail.getSettlementFreight(), runningWaterType);
            strategyMap.get(NetworkDriverAccountEnum.RunningWaterStatus.SETTLEMENT.getCode()).accept(settlementDriverDetail);
            strategyMap.get(NetworkDriverAccountEnum.RunningWaterStatus.CASE_OUT_FROZEN.getCode()).accept(settlementDriverDetail);
        }
    }

    @Override
    public IPage<APPNetworkDriverRunningWaterRecordVO> pageFrozenList(NetworkDriverPageParam param) {
        Long userNo = TokenUtil.getLoginUserInfo().getUserNo();
        param.setUserNo(userNo);
        return networkDriverRunningWaterRecordDao.pageFrozenList(param);
    }

    @Override
    public IPage<APPNetworkDriverRunningWaterRecordVO> runningWaterList(NetworkDriverPageParam param) {
        Long userNo = TokenUtil.getLoginUserInfo().getUserNo();
        param.setUserNo(userNo);
        IPage<APPNetworkDriverRunningWaterRecordVO> page = networkDriverRunningWaterRecordDao.runningWaterList(param);
        if (NetworkDriverAccountEnum.FundType.EXPENDITURE.getCode().equals(param.getFundType())) {
            if (CollectionUtil.isNotEmpty(page.getRecords())) {
                for (APPNetworkDriverRunningWaterRecordVO record : page.getRecords()) {
                    record.setAlterationBalance(record.getAlterationBalance().negate());
                }
            }
        } else if (param.getFundType() == null ) {
            if (CollectionUtil.isNotEmpty(page.getRecords())) {
                for (APPNetworkDriverRunningWaterRecordVO record : page.getRecords()) {
                    if (NetworkDriverAccountEnum.RunningWaterStatus.CASE_OUT_SUCCESS.getCode().equals( record.getRunningWaterType())){
                        record.setAlterationBalance(record.getAlterationBalance().negate());
                    }
                }
            }
        }

        return page;
    }

    @Override
    public void generateNetworkCaseOutRecord(SettlementDriverDetail settlementDriverDetail) {
        BankCardVO bankCardVO = Optional.ofNullable(driverFeign.getDriverCardInfo(settlementDriverDetail.getDriverUserNo()))
                .filter(Result::succeed).map(Result::getData).orElseThrow(ResultCodeEnum.FAIL);
        NetworkCaseOutRecord build = NetworkCaseOutRecord.builder()
                .caseOutNo(idGenerateSnowFlake.nextId(4L))
                .driverUserNo(settlementDriverDetail.getDriverUserNo())
                .driverUserName(settlementDriverDetail.getDriverName()).mobile(bankCardVO.getMobile())
                .status(NetworkDriverAccountEnum.CaseOutRecordStatus.WAIT_PLATFORM_PAY.getCode())
                .statusMsg(NetworkDriverAccountEnum.CaseOutRecordStatus.WAIT_PLATFORM_PAY.getMsg())
                .bank(bankCardVO.getBank()).collectionBankCode(bankCardVO.getCardNo())
                .payee(bankCardVO.getName()).alterationBalance(settlementDriverDetail.getSettlementFreight())
                .orderNo(settlementDriverDetail.getOrderNo()).orderGoodsNo(settlementDriverDetail.getOrderGoodsNo())
                .childNo(settlementDriverDetail.getChildNo())
                .platform("网运平台").createBy("系统").build();
        networkCaseOutRecordDao.saveEntity(build);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        strategyMap.put(NetworkDriverAccountEnum.RunningWaterStatus.SETTLEMENT.getCode(), this::generateSettlementRunningWaterRecord);
        strategyMap.put(NetworkDriverAccountEnum.RunningWaterStatus.CASE_OUT_FROZEN.getCode(), this::generateCaseOutFrozenRunningWaterRecord);
        strategyMap.put(NetworkDriverAccountEnum.RunningWaterStatus.CASE_OUT_SUCCESS.getCode(), this::generateCaseOutSuccessRunningWaterRecord);
    }
}

