package com.zanxiang.game.back.serve.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zanxiang.advertising.tencent.base.AdvertisingTencentServer;
import com.zanxiang.advertising.tencent.base.rpc.IUserActionSetRpc;
import com.zanxiang.erp.base.ErpServer;
import com.zanxiang.erp.base.rpc.ISysUserRpc;
import com.zanxiang.erp.security.util.SecurityUtil;
import com.zanxiang.game.back.serve.dao.mapper.GameBackPolicyMapper;
import com.zanxiang.game.back.serve.pojo.BackPolicyOfSplitLevel;
import com.zanxiang.game.back.serve.pojo.BackPolicyOfSumRecharge;
import com.zanxiang.game.back.serve.pojo.TutorialFinish;
import com.zanxiang.game.back.serve.pojo.dto.GameBackPolicyDTO;
import com.zanxiang.game.back.serve.pojo.dto.GameBackPolicyListDTO;
import com.zanxiang.game.back.serve.pojo.entity.GameBackPolicy;
import com.zanxiang.game.back.serve.pojo.vo.GameBackPolicyVO;
import com.zanxiang.game.back.serve.service.IGameBackPolicyService;
import com.zanxiang.game.back.serve.service.IGameTencentBackLogService;
import com.zanxiang.game.back.serve.service.IGameTencentOrderService;
import com.zanxiang.game.back.serve.service.IGameTencentUserService;
import com.zanxiang.module.util.JsonUtil;
import com.zanxiang.module.util.NumberUtil;
import com.zanxiang.module.util.bean.BeanUtil;
import com.zanxiang.module.util.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 游戏回传策略表 服务实现类
 * </p>
 *
 * @author auto
 * @since 2023-06-01
 */
@Slf4j
@Service
public class GameBackPolicyServiceImpl extends ServiceImpl<GameBackPolicyMapper, GameBackPolicy> implements IGameBackPolicyService {
    @Autowired
    private IGameTencentBackLogService gameTencentBackLogService;
    @Autowired
    private IGameTencentOrderService gameTencentOrderService;
    @Autowired
    private IGameTencentUserService gameTencentUserService;
    @Autowired
    private IGameBackPolicyService gameBackPolicyService;
    @DubboReference(providedBy = AdvertisingTencentServer.SERVER_DUBBO_NAME)
    private IUserActionSetRpc userActionSetRpc;
    @DubboReference(providedBy = ErpServer.SERVER_DUBBO_NAME)
    private ISysUserRpc sysUserRpc;

    @Override
    public IPage<GameBackPolicyVO> policyList(GameBackPolicyListDTO dto) {
        return gameBackPolicyService.page(dto.toPage(), new LambdaQueryWrapper<GameBackPolicy>()
                        .like(StringUtils.isNotBlank(dto.getBackPolicyName()), GameBackPolicy::getBackPolicyName, dto.getBackPolicyName())
                        .eq(GameBackPolicy::getCreateBy, SecurityUtil.getUserId())
                        .orderByDesc(GameBackPolicy::getCreateTime))
                .convert(this::toVO);
    }

    @Override
    public List<GameBackPolicyVO> allOfUser() {
        return list(new LambdaQueryWrapper<GameBackPolicy>()
                .eq(GameBackPolicy::getCreateBy, SecurityUtil.getUserId())
                .orderByDesc(GameBackPolicy::getCreateTime)
        ).stream().map(this::toVOSimple).collect(Collectors.toList());
    }

    @Override
    public boolean createPolicy(GameBackPolicyDTO dto) {
        if (nameExist(null, SecurityUtil.getUserId(), dto.getBackPolicyName())) {
            throw new BaseException("回传策略名重复");
        }
        GameBackPolicy backPolicy = GameBackPolicy.builder()
                .backPolicyName(dto.getBackPolicyName())
                .policyType(dto.getPolicyType())
                .createBy(SecurityUtil.getUserId())
                .createTime(LocalDateTime.now())
                .build();
        if (Objects.equals(dto.getPolicyType(), GameBackPolicy.TYPE_DEFAULT)) {
            backPolicy.setFirstMinMoney(NumberUtil.multiply100(dto.getFirstMinMoney()).longValue());
            backPolicy.setFirstMinMoneyType(dto.getFirstMinMoneyType());
            backPolicy.setFirstMinMoneyRate(dto.getFirstMinMoneyRate());
            backPolicy.setFirstMaxMoney(NumberUtil.multiply100(dto.getFirstMaxMoney()).longValue());
            backPolicy.setFirstMaxMoneyType(dto.getFirstMaxMoneyType());
            backPolicy.setFirstMaxMoneyRate(dto.getFirstMaxMoneyRate());
            backPolicy.setFirstOtherMoneyType(dto.getFirstOtherMoneyType());
            backPolicy.setFirstOtherMoneyRate(dto.getFirstOtherMoneyRate());
            backPolicy.setFirstDownLevel(downLevelToString(dto.getFirstDownLevel()));
            backPolicy.setFirstBackCountOfUser(dto.getFirstBackCountOfUser());
            backPolicy.setRechargeMinMoney(NumberUtil.multiply100(dto.getRechargeMinMoney()).longValue());
            backPolicy.setRechargeMinMoneyType(dto.getRechargeMinMoneyType());
            backPolicy.setRechargeMinMoneyRate(dto.getRechargeMinMoneyRate());
            backPolicy.setRechargeMaxMoney(NumberUtil.multiply100(dto.getRechargeMaxMoney()).longValue());
            backPolicy.setRechargeMaxMoneyType(dto.getRechargeMaxMoneyType());
            backPolicy.setRechargeMaxMoneyRate(dto.getRechargeMaxMoneyRate());
            backPolicy.setRechargeOtherMoneyType(dto.getRechargeOtherMoneyType());
            backPolicy.setRechargeOtherMoneyRate(dto.getRechargeOtherMoneyRate());
            backPolicy.setRechargeDownLevel(downLevelToString(dto.getRechargeDownLevel()));
            backPolicy.setRechargeBackCountOfUser(dto.getRechargeBackCountOfUser());
            backPolicy.setRegPayIntervalTime(dto.getRegPayIntervalTime());
            backPolicy.setBackUnit(dto.getBackUnit());
            backPolicy.setMarkUpOrder(dto.getMarkUpOrder());
            backPolicy.setMarkUpOrderMinMoney(dto.getMarkUpOrderMinMoney() == null ? null : NumberUtil.multiply100(dto.getMarkUpOrderMinMoney()).longValue());
            backPolicy.setMarkUpOrderMinMoneyType(dto.getMarkUpOrderMinMoneyType());
            backPolicy.setMarkUpOrderMinMoneyRate(dto.getMarkUpOrderMinMoneyRate());
            backPolicy.setMarkUpOrderMaxMoney(dto.getMarkUpOrderMaxMoney() == null ? null : NumberUtil.multiply100(dto.getMarkUpOrderMaxMoney()).longValue());
            backPolicy.setMarkUpOrderMaxMoneyType(dto.getMarkUpOrderMaxMoneyType());
            backPolicy.setMarkUpOrderMaxMoneyRate(dto.getMarkUpOrderMaxMoneyRate());
            backPolicy.setMarkUpOrderOtherMoneyType(dto.getMarkUpOrderOtherMoneyType());
            backPolicy.setMarkUpOrderOtherMoneyRate(dto.getMarkUpOrderOtherMoneyRate());
            backPolicy.setMarkUpDownLevel(downLevelToString(dto.getMarkUpDownLevel()));
            backPolicy.setMarkUpBackCountOfUser(dto.getMarkUpBackCountOfUser());
            backPolicy.setLargeAmount(dto.getLargeAmount() == null ? null : NumberUtil.multiply100(dto.getLargeAmount()).longValue());
            backPolicy.setSupperSmallAmount(dto.getSupperSmallAmount() == null ? null : NumberUtil.multiply100(dto.getSupperSmallAmount()).longValue());
            backPolicy.setSplitStrategy(CollectionUtils.isEmpty(dto.getSplitStrategy()) ? null : JsonUtil.toString(dto.getSplitStrategy()));
            backPolicy.setActiveBackSwitch(dto.getActiveBackSwitch());
            backPolicy.setRoleBackSwitch(dto.getRoleBackSwitch());
            backPolicy.setRoleLevelMin(dto.getRoleLevelMin());
            backPolicy.setTutorialFinishJson(JsonUtil.toString(dto.getTutorialFinish()));
            backPolicy.setLinkCallBack(dto.getLinkCallBack());
        } else if (Objects.equals(dto.getPolicyType(), GameBackPolicy.TYPE_SUM_RECHARGE)) {
            backPolicy.setTypeOfSumRechargeJson(JsonUtil.toString(dto.getTypeOfSumRecharge()));
            backPolicy.setRegPayIntervalTime(dto.getTypeOfSumRecharge().getRegPayIntervalTime());
            backPolicy.setActiveBackSwitch(dto.getTypeOfSumRecharge().getActiveBackSwitch());
            backPolicy.setRoleBackSwitch(dto.getTypeOfSumRecharge().getRoleBackSwitch());
            backPolicy.setRoleLevelMin(dto.getTypeOfSumRecharge().getRoleLevelMin());
            backPolicy.setTutorialFinishJson(JsonUtil.toString(dto.getTypeOfSumRecharge().getTutorialFinish()));
            backPolicy.setLinkCallBack(dto.getTypeOfSumRecharge().getLinkCallBack());
        } else if (Objects.equals(dto.getPolicyType(), GameBackPolicy.TYPE_SPLIT_LEVEL)) {
            backPolicy.setTypeOfSplitLevelJson(JsonUtil.toString(dto.getTypeOfSplitLevel()));
            backPolicy.setRegPayIntervalTime(dto.getTypeOfSplitLevel().getRegPayIntervalTime());
            backPolicy.setActiveBackSwitch(dto.getTypeOfSplitLevel().getActiveBackSwitch());
            backPolicy.setRoleBackSwitch(dto.getTypeOfSplitLevel().getRoleBackSwitch());
            backPolicy.setRoleLevelMin(dto.getTypeOfSplitLevel().getRoleLevelMin());
            backPolicy.setTutorialFinishJson(JsonUtil.toString(dto.getTypeOfSplitLevel().getTutorialFinish()));
            backPolicy.setLinkCallBack(dto.getTypeOfSplitLevel().getLinkCallBack());
        }
        return gameBackPolicyService.save(backPolicy);
    }

    @Override
    public boolean updatePolicy(Long policyId, GameBackPolicyDTO dto) {
        if (nameExist(policyId, SecurityUtil.getUserId(), dto.getBackPolicyName())) {
            throw new BaseException("回传策略名重复");
        }
        GameBackPolicy old = getById(policyId);
        GameBackPolicy backPolicy = GameBackPolicy.builder()
                .id(policyId)
                .backPolicyName(dto.getBackPolicyName())
                .createBy(old.getCreateBy())
                .createTime(old.getCreateTime())
                .updateBy(SecurityUtil.getUserId())
                .updateTime(LocalDateTime.now())
                .build();
        if (Objects.equals(dto.getPolicyType(), GameBackPolicy.TYPE_DEFAULT)) {
            backPolicy.setFirstMinMoney(NumberUtil.multiply100(dto.getFirstMinMoney()).longValue());
            backPolicy.setFirstMinMoneyType(dto.getFirstMinMoneyType());
            backPolicy.setFirstMinMoneyRate(dto.getFirstMinMoneyRate());
            backPolicy.setFirstMaxMoney(NumberUtil.multiply100(dto.getFirstMaxMoney()).longValue());
            backPolicy.setFirstMaxMoneyType(dto.getFirstMaxMoneyType());
            backPolicy.setFirstMaxMoneyRate(dto.getFirstMaxMoneyRate());
            backPolicy.setFirstOtherMoneyType(dto.getFirstOtherMoneyType());
            backPolicy.setFirstOtherMoneyRate(dto.getFirstOtherMoneyRate());
            backPolicy.setFirstDownLevel(downLevelToString(dto.getFirstDownLevel()));
            backPolicy.setFirstBackCountOfUser(dto.getFirstBackCountOfUser());
            backPolicy.setRechargeMinMoney(NumberUtil.multiply100(dto.getRechargeMinMoney()).longValue());
            backPolicy.setRechargeMinMoneyType(dto.getRechargeMinMoneyType());
            backPolicy.setRechargeMinMoneyRate(dto.getRechargeMinMoneyRate());
            backPolicy.setRechargeMaxMoney(NumberUtil.multiply100(dto.getRechargeMaxMoney()).longValue());
            backPolicy.setRechargeMaxMoneyType(dto.getRechargeMaxMoneyType());
            backPolicy.setRechargeMaxMoneyRate(dto.getRechargeMaxMoneyRate());
            backPolicy.setRechargeOtherMoneyType(dto.getRechargeOtherMoneyType());
            backPolicy.setRechargeOtherMoneyRate(dto.getRechargeOtherMoneyRate());
            backPolicy.setRechargeDownLevel(downLevelToString(dto.getRechargeDownLevel()));
            backPolicy.setRechargeBackCountOfUser(dto.getRechargeBackCountOfUser());
            backPolicy.setRegPayIntervalTime(dto.getRegPayIntervalTime());
            backPolicy.setBackUnit(dto.getBackUnit());
            backPolicy.setMarkUpOrder(dto.getMarkUpOrder());
            backPolicy.setMarkUpOrderMinMoney(dto.getMarkUpOrderMinMoney() == null ? null : NumberUtil.multiply100(dto.getMarkUpOrderMinMoney()).longValue());
            backPolicy.setMarkUpOrderMinMoneyType(dto.getMarkUpOrderMinMoneyType());
            backPolicy.setMarkUpOrderMinMoneyRate(dto.getMarkUpOrderMinMoneyRate());
            backPolicy.setMarkUpOrderMaxMoney(dto.getMarkUpOrderMaxMoney() == null ? null : NumberUtil.multiply100(dto.getMarkUpOrderMaxMoney()).longValue());
            backPolicy.setMarkUpOrderMaxMoneyType(dto.getMarkUpOrderMaxMoneyType());
            backPolicy.setMarkUpOrderMaxMoneyRate(dto.getMarkUpOrderMaxMoneyRate());
            backPolicy.setMarkUpOrderOtherMoneyType(dto.getMarkUpOrderOtherMoneyType());
            backPolicy.setMarkUpOrderOtherMoneyRate(dto.getMarkUpOrderOtherMoneyRate());
            backPolicy.setMarkUpDownLevel(downLevelToString(dto.getMarkUpDownLevel()));
            backPolicy.setMarkUpBackCountOfUser(dto.getMarkUpBackCountOfUser());
            backPolicy.setLargeAmount(dto.getLargeAmount() == null ? null : NumberUtil.multiply100(dto.getLargeAmount()).longValue());
            backPolicy.setSupperSmallAmount(dto.getSupperSmallAmount() == null ? null : NumberUtil.multiply100(dto.getSupperSmallAmount()).longValue());
            backPolicy.setSplitStrategy(CollectionUtils.isEmpty(dto.getSplitStrategy()) ? null : JsonUtil.toString(dto.getSplitStrategy()));
            backPolicy.setActiveBackSwitch(dto.getActiveBackSwitch());
            backPolicy.setRoleBackSwitch(dto.getRoleBackSwitch());
            backPolicy.setRoleLevelMin(dto.getRoleLevelMin());
            backPolicy.setTutorialFinishJson(JsonUtil.toString(dto.getTutorialFinish()));
            backPolicy.setLinkCallBack(dto.getLinkCallBack());
        } else if (Objects.equals(dto.getPolicyType(), GameBackPolicy.TYPE_SUM_RECHARGE)) {
            backPolicy.setTypeOfSumRechargeJson(JsonUtil.toString(dto.getTypeOfSumRecharge()));
            backPolicy.setRegPayIntervalTime(dto.getTypeOfSumRecharge().getRegPayIntervalTime());
            backPolicy.setActiveBackSwitch(dto.getTypeOfSumRecharge().getActiveBackSwitch());
            backPolicy.setRoleBackSwitch(dto.getTypeOfSumRecharge().getRoleBackSwitch());
            backPolicy.setRoleLevelMin(dto.getTypeOfSumRecharge().getRoleLevelMin());
            backPolicy.setTutorialFinishJson(JsonUtil.toString(dto.getTypeOfSumRecharge().getTutorialFinish()));
            backPolicy.setLinkCallBack(dto.getTypeOfSumRecharge().getLinkCallBack());
        } else if (Objects.equals(dto.getPolicyType(), GameBackPolicy.TYPE_SPLIT_LEVEL)) {
            backPolicy.setTypeOfSplitLevelJson(JsonUtil.toString(dto.getTypeOfSplitLevel()));
            backPolicy.setRegPayIntervalTime(dto.getTypeOfSplitLevel().getRegPayIntervalTime());
            backPolicy.setActiveBackSwitch(dto.getTypeOfSplitLevel().getActiveBackSwitch());
            backPolicy.setRoleBackSwitch(dto.getTypeOfSplitLevel().getRoleBackSwitch());
            backPolicy.setRoleLevelMin(dto.getTypeOfSplitLevel().getRoleLevelMin());
            backPolicy.setTutorialFinishJson(JsonUtil.toString(dto.getTypeOfSplitLevel().getTutorialFinish()));
            backPolicy.setLinkCallBack(dto.getTypeOfSplitLevel().getLinkCallBack());
        }
        return gameBackPolicyService.updateById(backPolicy);
    }

    @Override
    public boolean deletePolicy(List<Long> ids) {
        return gameBackPolicyService.removeByIds(ids);
    }

    private boolean nameExist(Long policyId, Long userId, String policyName) {
        return count(new LambdaQueryWrapper<GameBackPolicy>()
                .ne(policyId != null, GameBackPolicy::getId, policyId)
                .eq(GameBackPolicy::getBackPolicyName, policyName)
                .eq(GameBackPolicy::getCreateBy, userId)
        ) > 0;
    }

    private GameBackPolicyVO toVOSimple(GameBackPolicy gameBackPolicy) {
        if (gameBackPolicy == null) {
            return null;
        }
        GameBackPolicyVO vo = BeanUtil.copy(gameBackPolicy, GameBackPolicyVO.class);
        if (gameBackPolicy.getPolicyType() == null || Objects.equals(gameBackPolicy.getPolicyType(), GameBackPolicy.TYPE_DEFAULT)) {
            vo.setLargeAmount(gameBackPolicy.getLargeAmount() == null ? null : NumberUtil.divide100(new BigDecimal(gameBackPolicy.getLargeAmount())));
            vo.setSupperSmallAmount(gameBackPolicy.getSupperSmallAmount() == null ? null : NumberUtil.divide100(new BigDecimal(gameBackPolicy.getSupperSmallAmount())));
            vo.setFirstMinMoney(NumberUtil.divide100(new BigDecimal(gameBackPolicy.getFirstMinMoney())));
            vo.setFirstMaxMoney(NumberUtil.divide100(new BigDecimal(gameBackPolicy.getFirstMaxMoney())));
            vo.setRechargeMinMoney(NumberUtil.divide100(new BigDecimal(gameBackPolicy.getRechargeMinMoney())));
            vo.setRechargeMaxMoney(NumberUtil.divide100(new BigDecimal(gameBackPolicy.getRechargeMaxMoney())));
            if (gameBackPolicy.getMarkUpOrderMinMoney() != null) {
                vo.setMarkUpOrderMinMoney(NumberUtil.divide100(new BigDecimal(gameBackPolicy.getMarkUpOrderMinMoney())));
            }
            if (gameBackPolicy.getMarkUpOrderMaxMoney() != null) {
                vo.setMarkUpOrderMaxMoney(NumberUtil.divide100(new BigDecimal(gameBackPolicy.getMarkUpOrderMaxMoney())));
            }
            if (StringUtils.isNotBlank(gameBackPolicy.getFirstDownLevel())) {
                vo.setFirstDownLevel(Arrays.stream(gameBackPolicy.getFirstDownLevel().split(","))
                        .map(this::transformDownLevel)
                        .collect(Collectors.toList())
                );
            }
            if (StringUtils.isNotBlank(gameBackPolicy.getRechargeDownLevel())) {
                vo.setRechargeDownLevel(Arrays.stream(gameBackPolicy.getRechargeDownLevel().split(","))
                        .map(this::transformDownLevel)
                        .collect(Collectors.toList())
                );
            }
            if (StringUtils.isNotBlank(gameBackPolicy.getMarkUpDownLevel())) {
                vo.setMarkUpDownLevel(Arrays.stream(gameBackPolicy.getMarkUpDownLevel().split(","))
                        .map(this::transformDownLevel)
                        .collect(Collectors.toList())
                );
            }
            if (StringUtils.isNotBlank(gameBackPolicy.getSplitStrategy())) {
                vo.setSplitStrategy((List<GameBackPolicyVO.SplitStrategy>) JsonUtil.toList(gameBackPolicy.getSplitStrategy(), List.class, GameBackPolicyVO.SplitStrategy.class));
            }
            if (StringUtils.isNotBlank(gameBackPolicy.getTutorialFinishJson())) {
                vo.setTutorialFinish(JsonUtil.toObj(gameBackPolicy.getTutorialFinishJson(), TutorialFinish.class));
            }
        } else if (Objects.equals(gameBackPolicy.getPolicyType(), GameBackPolicy.TYPE_SUM_RECHARGE)) {
            vo.setTypeOfSumRecharge(JsonUtil.toObj(gameBackPolicy.getTypeOfSumRechargeJson(), BackPolicyOfSumRecharge.class));
        } else if (Objects.equals(gameBackPolicy.getPolicyType(), GameBackPolicy.TYPE_SPLIT_LEVEL)) {
            vo.setTypeOfSplitLevel(JsonUtil.toObj(gameBackPolicy.getTypeOfSplitLevelJson(), BackPolicyOfSplitLevel.class));
        } else {
            throw new BaseException("未知的回传类型");
        }
        return vo;
    }

    private GameBackPolicyVO toVO(GameBackPolicy gameBackPolicy) {
        if (gameBackPolicy == null) {
            return null;
        }
        GameBackPolicyVO vo = toVOSimple(gameBackPolicy);
        vo.setCreateName(sysUserRpc.getById(gameBackPolicy.getCreateBy()).getData().getNickname());
        return vo;
    }

    private GameBackPolicyVO.PolicyDownLevel transformDownLevel(String downLevel) {
        String[] tmp = downLevel.split("_");
        return GameBackPolicyVO.PolicyDownLevel.builder()
                .minMoney(NumberUtil.divide100(new BigDecimal(Long.parseLong(tmp[0]))))
                .maxMoney(NumberUtil.divide100(new BigDecimal(Long.parseLong(tmp[1]))))
                .backMoney(NumberUtil.divide100(new BigDecimal(Long.parseLong(tmp[2]))))
                .build();
    }

    private String downLevelToString(List<GameBackPolicyVO.PolicyDownLevel> downLevelList) {
        if (CollectionUtils.isEmpty(downLevelList)) {
            return null;
        }
        downLevelList.sort((val1, val2) -> val1.getMinMoney().compareTo(val2.getMinMoney()));
        return StringUtils.join(downLevelList.stream().map(this::downLevelToString).collect(Collectors.toList()), ",");
    }

    private String downLevelToString(GameBackPolicyVO.PolicyDownLevel downLevel) {
        return NumberUtil.multiply100(downLevel.getMinMoney()).longValue() + "_" +
                NumberUtil.multiply100(downLevel.getMaxMoney()).longValue() + "_" +
                NumberUtil.multiply100(downLevel.getBackMoney()).longValue();
    }
}
