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

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.clx.performance.component.IdGenerateSnowFlake;
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.NetworkDriverAccount;
import com.clx.performance.model.settle.NetworkDriverRunningWaterRecord;
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.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;

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

    private final static Map<Integer, BiConsumer<NetworkDriverAccount, BigDecimal>> strategyMap = new HashMap<>();

    private final NetworkDriverRunningWaterRecordDao networkDriverRunningWaterRecordDao;

    private final NetworkDriverAccountDao networkDriverAccountDao;

    private final IdGenerateSnowFlake idGenerateSnowFlake;

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateSettlementRunningWaterRecord(NetworkDriverAccount networkDriverAccount, BigDecimal money) {
        NetworkDriverAccount build = NetworkDriverAccount.builder().id(networkDriverAccount.getId())
                .usableBalance(money)
                .frozenBalance(BigDecimal.ZERO)
                .accountBalance(money).build();
        while (true) {
            NetworkDriverAccount account = networkDriverAccountDao.getEntityByKey(build.getId()).get();
            build.setModifiedTime(account.getModifiedTime());
            Integer i = networkDriverAccountDao.updateAccountCAS(build, LocalDateTime.now(), true);
            if (i == 1) {
                account = networkDriverAccountDao.getEntityByKey(build.getId()).get();
                NetworkDriverRunningWaterRecord entity = NetworkDriverRunningWaterRecord.builder()
                        .usableBalance(account.getUsableBalance())
                        .alterationBalance(money).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())

                        .build();

                networkDriverRunningWaterRecordDao.saveEntity(entity);
                break;
            }
        }

    }

    @Override
    public void generateCaseOutFrozenRunningWaterRecord(NetworkDriverAccount networkDriverAccount, BigDecimal money) {
        NetworkDriverAccount build = NetworkDriverAccount.builder().id(networkDriverAccount.getId())
                .frozenBalance(money)
                .accountBalance(BigDecimal.ZERO)
                .usableBalance(money).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) {
                account = networkDriverAccountDao.getEntityByKey(build.getId()).get();
                NetworkDriverRunningWaterRecord entity = NetworkDriverRunningWaterRecord.builder()
                        .usableBalance(account.getUsableBalance())
                        .alterationBalance(money).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())
                        .runningWaterType(NetworkDriverAccountEnum.RunningWaterStatus.CASE_OUT_FROZEN.getCode())

                        .build();

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

    @Override
    public void generateCaseOutSuccessRunningWaterRecord(NetworkDriverAccount networkDriverAccount, BigDecimal money) {
        NetworkDriverAccount build = NetworkDriverAccount.builder().id(networkDriverAccount.getId())
                .frozenBalance(money.negate())
                .usableBalance(BigDecimal.ZERO)
                .accountBalance(money).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) {
                account = networkDriverAccountDao.getEntityByKey(build.getId()).get();
                NetworkDriverRunningWaterRecord entity = NetworkDriverRunningWaterRecord.builder()
                        .usableBalance(account.getUsableBalance())
                        .alterationBalance(money).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())

                        .build();

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

    @Override
    public void generateNetworkDriverRunningWaterRecord(NetworkDriverAccount networkDriverAccount, BigDecimal money, Integer runningWaterType) {
        strategyMap.get(runningWaterType).accept(networkDriverAccount, money);
    }

    @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);
        return networkDriverRunningWaterRecordDao.runningWaterList(param);
    }

    @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);
    }
}
