package com.zanxiang.game.module.manage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zanxiang.game.module.base.pojo.enums.*;
import com.zanxiang.game.module.manage.pojo.dto.*;
import com.zanxiang.game.module.manage.pojo.params.GamePayWayAddUpdateParam;
import com.zanxiang.game.module.manage.pojo.params.GamePayWayListParam;
import com.zanxiang.game.module.manage.pojo.vo.GamePayWayListVO;
import com.zanxiang.game.module.manage.pojo.vo.GamePayWayVO;
import com.zanxiang.game.module.manage.service.*;
import com.zanxiang.game.module.mybatis.entity.GameApplet;
import com.zanxiang.game.module.mybatis.entity.GamePayWay;
import com.zanxiang.game.module.mybatis.mapper.GamePayWayMapper;
import com.zanxiang.module.util.JsonUtil;
import com.zanxiang.module.util.bean.BeanUtil;
import com.zanxiang.module.util.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author : lingfeng
 * @time : 2022-06-23
 * @description : 游戏支付配置
 */
@Service
@Slf4j
public class GamePayWayServiceImpl extends ServiceImpl<GamePayWayMapper, GamePayWay> implements IGamePayWayService {

    @Autowired
    private IGameAppletService gameAppletService;

    @Autowired
    private IGameService gameService;

    @Autowired
    private IPayDeviceService payDeviceService;

    @Autowired
    private IPayWayService payWayService;

    @Autowired
    private IPayBoxService payBoxService;

    @Autowired
    private IPayApplicationService payApplicationService;

    @Autowired
    private IPayMerchantService payMerchantService;

    @Autowired
    private IMiPaySumService miPaySumService;

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public boolean addOrUpdate(GamePayWayAddUpdateParam param) {
        GamePayWay gamePayWay = param.getId() != null ? super.getById(param.getId()) : GamePayWay.builder()
                .gameId(param.getGameId())
                .payWayId(param.getPayWayId())
                .payDeviceId(param.getPayDeviceId())
                .payName(PayWayEnum.getNameByPayWayId(param.getPayWayId()) + PayDeviceEnum.getByPayWayId(param.getPayDeviceId()))
                .remark(param.getRemark())
                .status(StatusEnum.YES.getCode())
                .isDelete(DeleteEnum.NO.getCode())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();
        if (gamePayWay == null) {
            throw new BaseException("参数错误, 游戏支付配置信息不存在");
        }
        //支付方式
        Long payWayId = gamePayWay.getPayWayId();
        if (Objects.equals(PayWayEnum.ALI_PAY.getPayWayId(), payWayId.intValue())) {
            GamePayWayAddUpdateParam.AliPayConfigBean aliPayConfig = param.getAliPayConfig();
            if (aliPayConfig == null || Strings.isBlank(aliPayConfig.getAppId())) {
                throw new BaseException("参数错误, 支付宝支付配置为空");
            }
            if (!Objects.equals(aliPayConfig.getAppId(), gamePayWay.getAppId())) {
                PayApplicationDTO payApplicationDTO = payApplicationService.getByAppId(aliPayConfig.getAppId());
                gamePayWay.setAppId(payApplicationDTO.getAppId());
                gamePayWay.setAppName(payApplicationDTO.getAppName());
                gamePayWay.setMerchantNo(payApplicationDTO.getMerchantNo());
            }
        }
        if (Objects.equals(PayWayEnum.WX_PAY.getPayWayId(), payWayId.intValue())) {
            GamePayWayAddUpdateParam.WxPayConfigBean wxPayConfig = param.getWxPayConfig();
            if (wxPayConfig == null) {
                throw new BaseException("参数错误, 微信支付参数配置为空");
            }
            Long payDeviceId = gamePayWay.getPayDeviceId();
            if (Objects.equals(payDeviceId, PayDeviceEnum.PC_PAY.getPayDeviceId())
                    || Objects.equals(payDeviceId, PayDeviceEnum.H5_PAY.getPayDeviceId())) {
                if (StringUtils.isAnyEmpty(wxPayConfig.getAppId(), wxPayConfig.getMerchantNo())) {
                    throw new BaseException("参数错误, PC二维码和H5支付, 缺少商户号");
                }
            }
            if (Objects.equals(payDeviceId, PayDeviceEnum.APPLET_PAY.getPayDeviceId())
                    || Objects.equals(payDeviceId, PayDeviceEnum.CUSTOM_PAY.getPayDeviceId())) {
                if (wxPayConfig.getPayBoxId() == null) {
                    throw new BaseException("参数错误, 小程序支付和客服支付缺少盒子id");
                }
                if (Objects.equals(payDeviceId, PayDeviceEnum.CUSTOM_PAY.getPayDeviceId()) && Strings.isBlank(wxPayConfig.getThumbUrl())) {
                    throw new BaseException("参数错误, 客服支付缺少消息图片地址");
                }
            }
            if (!Objects.equals(wxPayConfig.getAppId(), gamePayWay.getAppId())) {
                PayApplicationDTO payApplicationDTO = payApplicationService.getByAppId(wxPayConfig.getAppId());
                gamePayWay.setAppId(payApplicationDTO.getAppId());
                gamePayWay.setAppName(payApplicationDTO.getAppName());
            }
            gamePayWay.setMerchantNo(wxPayConfig.getMerchantNo());
            gamePayWay.setPayBoxId(wxPayConfig.getPayBoxId());
            gamePayWay.setThumbUrl(wxPayConfig.getThumbUrl());
        }
        if (Objects.equals(PayWayEnum.MI_PAY.getPayWayId(), payWayId.intValue())) {
            GamePayWayAddUpdateParam.MiPayConfigBean miPayConfig = param.getMiPayConfig();
            if (miPayConfig == null || StringUtils.isAnyEmpty(miPayConfig.getAppId(), miPayConfig.getAppKey(), miPayConfig.getAppKeyDev())) {
                throw new BaseException("参数错误, 米大师支付参数配置不全");
            }
            GameAppletDTO gameAppletDTO = gameAppletService.getByGameId(gamePayWay.getGameId());
            if (gameAppletDTO != null) {
                gameAppletService.update(new LambdaUpdateWrapper<GameApplet>()
                        .set(GameApplet::getMiPayConfig, JsonUtil.toString(miPayConfig))
                        .set(GameApplet::getUpdateTime, LocalDateTime.now())
                        .eq(GameApplet::getGameId, gamePayWay.getGameId()));
                miPaySumService.add(param.getGameId(), gameAppletDTO.getAppId(), miPayConfig.getAppId());
            }
        }
        return super.saveOrUpdate(gamePayWay);
    }

    @Override
    public IPage<GamePayWayListVO> pageList(GamePayWayListParam param) {
        Map<Long, GameDTO> gameMap = gameService.gameMap();
        Map<Long, PayDeviceDTO> payDeviceMap = payDeviceService.payDeviceMap();
        Map<Long, PayWayDTO> payWayMap = payWayService.payWayMap();
        Map<String, PayMerchantDTO> payMerchantMap = payMerchantService.payMerchantMap();
        return super.page(param.toPage(), new LambdaQueryWrapper<GamePayWay>()
                .eq(param.getGameId() != null, GamePayWay::getGameId, param.getGameId())
                .eq(param.getPayWayId() != null, GamePayWay::getPayWayId, param.getPayWayId())
                .eq(param.getStatus() != null, GamePayWay::getStatus, param.getStatus())
                .orderByDesc(GamePayWay::getCreateTime))
                .convert(gamePayWay -> this.toVO(gameMap, gamePayWay, payMerchantMap, payWayMap, payDeviceMap));
    }

    private GamePayWayListVO toVO(Map<Long, GameDTO> gameMap, GamePayWay gamePayWay, Map<String, PayMerchantDTO> payMerchantMap,
                                  Map<Long, PayWayDTO> payWayMap, Map<Long, PayDeviceDTO> payDeviceMap) {
        GamePayWayListVO gamePayWayListVO = BeanUtil.copy(gamePayWay, GamePayWayListVO.class);
        if (gamePayWayListVO == null) {
            return null;
        }
        //游戏信息
        GameDTO gameDTO = gameMap.get(gamePayWayListVO.getGameId());
        if (gameDTO != null) {
            gamePayWayListVO.setGameName(gameDTO.getName());
            GameCategoryEnum gameCategoryEnum = GameCategoryEnum.getGameCategory(gameDTO.getCategory());
            if (gameCategoryEnum != null) {
                gamePayWayListVO.setGameCategoryId(gameCategoryEnum.getId());
                gamePayWayListVO.setGameCategory(gameCategoryEnum.getName());
            }
        }
        //支付方式和类型
        Long payWayId = gamePayWay.getPayWayId();
        PayWayDTO payWayDTO = payWayMap.get(payWayId);
        if (payWayDTO != null) {
            gamePayWayListVO.setPayWayName(payWayDTO.getPayWayName());
        }
        PayDeviceDTO payDeviceDTO = payDeviceMap.get(gamePayWay.getPayDeviceId());
        if (payDeviceDTO != null) {
            gamePayWayListVO.setPayDeviceName(payDeviceDTO.getPayDeviceName());
        }
        //支付配置
        if (Objects.equals(PayWayEnum.ALI_PAY.getPayWayId(), payWayId.intValue())) {
            GamePayWayListVO.AliPayConfigBean aliPayConfigBean = new GamePayWayListVO.AliPayConfigBean();
            aliPayConfigBean.setAppId(gamePayWay.getAppId());
            gamePayWayListVO.setAliPayConfig(aliPayConfigBean);
        }
        if (Objects.equals(PayWayEnum.WX_PAY.getPayWayId(), payWayId.intValue())) {
            GamePayWayListVO.WxPayConfigBean wxPayConfigBean = new GamePayWayListVO.WxPayConfigBean();
            if (gamePayWay.getPayBoxId() != null) {
                PayBoxDTO payBoxDTO = payBoxService.getByPayBoxId(gamePayWay.getPayBoxId());
                wxPayConfigBean.setPayBoxId(gamePayWay.getPayBoxId());
                wxPayConfigBean.setPayBoxName(payBoxDTO.getName());
            }
            wxPayConfigBean.setThumbUrl(gamePayWay.getThumbUrl());
            wxPayConfigBean.setAppId(gamePayWay.getAppId());
            wxPayConfigBean.setAppName(gamePayWay.getAppName());
            wxPayConfigBean.setMerchantNo(gamePayWay.getMerchantNo());
            PayMerchantDTO payMerchantDTO = payMerchantMap.get(gamePayWay.getMerchantNo());
            if (payMerchantDTO != null) {
                wxPayConfigBean.setMerchantName(payMerchantDTO.getMerchantName());
            }
            gamePayWayListVO.setWxPayConfig(wxPayConfigBean);
        }
        if (Objects.equals(PayWayEnum.MI_PAY.getPayWayId(), payWayId.intValue())) {
            GameAppletDTO gameAppletDTO = gameAppletService.getByGameId(gamePayWay.getGameId());
            String miPayConfig = gameAppletDTO.getMiPayConfig();
            if (Strings.isNotBlank(miPayConfig)) {
                gamePayWayListVO.setMiPayConfig(JsonUtil.toObj(miPayConfig, GamePayWayListVO.MiPayConfigBean.class));
            }
        }
        //返回
        return gamePayWayListVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean statusUpdate(Long id, Integer status) {
        return super.update(new LambdaUpdateWrapper<GamePayWay>()
                .set(GamePayWay::getStatus, status)
                .set(GamePayWay::getUpdateTime, LocalDateTime.now())
                .eq(GamePayWay::getId, id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteById(Long id) {
        return super.removeById(id);
    }

    @Override
    public List<GamePayWayVO> getByGameId(Long gameId) {
        List<GamePayWay> gamePayWayList = super.list(new LambdaQueryWrapper<GamePayWay>()
                .eq(GamePayWay::getGameId, gameId));
        if (CollectionUtils.isEmpty(gamePayWayList)) {
            return Collections.emptyList();
        }
        List<Long> payDeviceIdList = gamePayWayList.stream().map(GamePayWay::getPayDeviceId).distinct().collect(Collectors.toList());
        Map<Long, PayDeviceDTO> payDeviceMap = payDeviceService.payDeviceMap();
        List<GamePayWayVO> list = new ArrayList<>();
        payDeviceIdList.forEach(payDeviceId -> list.add(GamePayWayVO.builder()
                .id(payDeviceId)
                .payWayName(payDeviceMap.get(payDeviceId).getPayDeviceName())
                .build()));
        return list;
    }

    @Override
    public Map<Long, PayDeviceDTO> getPayDeviceByGameId(Long gameId) {
        List<GamePayWay> gamePayWayList = super.list(new LambdaQueryWrapper<GamePayWay>()
                .eq(GamePayWay::getGameId, gameId));
        if (CollectionUtils.isEmpty(gamePayWayList)) {
            return Collections.emptyMap();
        }
        List<Long> payDeviceIdList = gamePayWayList.stream().map(GamePayWay::getPayDeviceId).distinct().collect(Collectors.toList());
        List<PayDeviceDTO> payDeviceDTOList = payDeviceService.listByIds(payDeviceIdList).stream()
                .map(payDevice -> BeanUtil.copy(payDevice, PayDeviceDTO.class))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(payDeviceDTOList)) {
            return Collections.emptyMap();
        }
        return payDeviceDTOList.stream().collect(Collectors.toMap(PayDeviceDTO::getId, Function.identity()));
    }

    @Override
    public Set<String> getGameMerchantNo(Long gameId) {
        List<GamePayWay> gamePayWayList = super.list(new LambdaQueryWrapper<GamePayWay>()
                .eq(GamePayWay::getGameId, gameId));
        if (CollectionUtils.isEmpty(gamePayWayList)) {
            return Collections.emptySet();
        }
        Set<String> merchantNoSet = new HashSet<>();
        gamePayWayList.forEach(gamePayWay -> {
            Long payBoxId = gamePayWay.getPayBoxId();
            if (payBoxId == null || Strings.isNotBlank(gamePayWay.getMerchantNo())) {
                merchantNoSet.add(gamePayWay.getMerchantNo());
            } else {
                PayBoxDTO payBoxDTO = payBoxService.getByPayBoxId(payBoxId);
                if (Strings.isNotBlank(payBoxDTO.getMerchantNos())) {
                    String[] merchantNoArray = payBoxDTO.getMerchantNos().split(",");
                    merchantNoSet.addAll(Arrays.asList(merchantNoArray));
                }
            }
        });
        return merchantNoSet;
    }
}
