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.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zanxiang.game.module.base.pojo.enums.DeleteEnum;
import com.zanxiang.game.module.base.pojo.enums.PayApplicationTypeEnum;
import com.zanxiang.game.module.base.pojo.enums.StatusEnum;
import com.zanxiang.game.module.manage.pojo.dto.PayApplicationDTO;
import com.zanxiang.game.module.manage.pojo.dto.PayBoxDTO;
import com.zanxiang.game.module.manage.pojo.dto.PayMerchantDTO;
import com.zanxiang.game.module.manage.pojo.params.PayBoxAddUpdateParam;
import com.zanxiang.game.module.manage.pojo.params.PayBoxListParam;
import com.zanxiang.game.module.manage.pojo.vo.PayBoxChoiceVO;
import com.zanxiang.game.module.manage.pojo.vo.PayBoxListVO;
import com.zanxiang.game.module.manage.service.IPayApplicationService;
import com.zanxiang.game.module.manage.service.IPayBoxService;
import com.zanxiang.game.module.manage.service.IPayMerchantService;
import com.zanxiang.game.module.mybatis.entity.PayBox;
import com.zanxiang.game.module.mybatis.mapper.PayBoxMapper;
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.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : lingfeng
 * @time : 2022-06-23
 * @description : 支付盒子
 */
@Component
@Slf4j
@Service
public class PayBoxServiceImpl extends ServiceImpl<PayBoxMapper, PayBox> implements IPayBoxService {

    @Resource
    private IPayMerchantService payMerchantService;

    @Autowired
    private IPayApplicationService payApplicationService;

    @Override
    public List<PayBoxChoiceVO> payBoxChoiceList() {
        return super.list(new LambdaQueryWrapper<PayBox>()
                        .select(PayBox::getId, PayBox::getType, PayBox::getName))
                .stream()
                .map(payBox -> BeanUtil.copy(payBox, PayBoxChoiceVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public IPage<PayBoxListVO> pageList(PayBoxListParam param) {
        //条件查询支付应用列表
        Map<String, PayApplicationDTO> payApplicationMap = payApplicationService.payApplicationCondition(param.getPayApplicationType(),
                param.getPayApplicationAppId(), param.getPayApplicationCompany());
        if (payApplicationMap != null && payApplicationMap.isEmpty()) {
            return new Page<>();
        }
        Set<String> payApplicationAppIdList = null;
        if (payApplicationMap == null) {
            payApplicationMap = payApplicationService.payApplicationMap();
        } else {
            payApplicationAppIdList = payApplicationMap.keySet();
        }
        //查询商户
        Map<String, PayMerchantDTO> payMerchantMap = payMerchantService.payMerchantCondition(param.getMerchantNo(), param.getMerchantName());
        if (payMerchantMap != null && payMerchantMap.isEmpty()) {
            return new Page<>();
        }
        String merchantIds = null;
        if (payMerchantMap == null) {
            payMerchantMap = payMerchantService.payMerchantMap();
        } else {
            merchantIds = String.join(",", payMerchantMap.keySet());
        }
        //执行查询
        Map<String, PayApplicationDTO> finalPayApplicationMap = payApplicationMap;
        Map<String, PayMerchantDTO> finalPayMerchantMap = payMerchantMap;
        return page(param.toPage(), new LambdaQueryWrapper<PayBox>()
                .like(Strings.isNotBlank(param.getName()), PayBox::getName, param.getName())
                .in(CollectionUtils.isNotEmpty(payApplicationAppIdList), PayBox::getAppId, payApplicationAppIdList)
                .apply(Strings.isNotBlank(merchantIds), "FIND_IN_SET ('" + merchantIds + "',merchant_nos)")
                .orderByDesc(PayBox::getCreateTime))
                .convert(payBox -> this.toVo(payBox, finalPayApplicationMap, finalPayMerchantMap));
    }

    private PayBoxListVO toVo(PayBox payBox, Map<String, PayApplicationDTO> payApplicationMap, Map<String, PayMerchantDTO> payMerchantMap) {
        PayBoxListVO payBoxListVO = BeanUtil.copy(payBox, PayBoxListVO.class);
        if (payBoxListVO == null) {
            return null;
        }
        PayApplicationDTO payApplicationDTO = payApplicationMap.get(payBox.getAppId());
        if (payApplicationDTO != null) {
            payBoxListVO.setPayApplicationName(payApplicationDTO.getAppName());
            payBoxListVO.setPayApplicationType(payApplicationDTO.getType());
            payBoxListVO.setPayApplicationTypeName(PayApplicationTypeEnum.getDescByType(payApplicationDTO.getType()));
            payBoxListVO.setPayApplicationAppId(payApplicationDTO.getAppId());
            payBoxListVO.setPayApplicationGhId(payApplicationDTO.getGhId());
            payBoxListVO.setPayApplicationCompany(payApplicationDTO.getCompany());
        }
        Map<String, String> merchantMap = new HashMap<>(payMerchantMap.size());
        if (Strings.isNotBlank(payBox.getMerchantNos())) {
            String[] merchantNoArray = payBox.getMerchantNos().split(",");
            for (String merchantNo : merchantNoArray) {
                PayMerchantDTO payMerchantDTO = payMerchantMap.get(merchantNo);
                if (payMerchantDTO == null) {
                    payMerchantDTO = payMerchantService.getByMerchantNo(merchantNo);
                }
                if (payMerchantDTO != null) {
                    merchantMap.put(merchantNo, payMerchantDTO.getMerchantName());
                }
            }
        }
        payBoxListVO.setPayMerchantMap(merchantMap);
        return payBoxListVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addOrUpdate(PayBoxAddUpdateParam param) {
        //查询支付应用
        PayApplicationDTO payApplicationDTO = payApplicationService.getByAppId(param.getPayApplicationAppId());
        Long id = param.getId();
        //更新
        if (id != null) {
            PayBox payBox = super.getById(id);
            if (payBox == null) {
                throw new BaseException("参数错误, 支付盒子信息不存在");
            }
            //判断名称是否已经存在
            this.payBoxNameCheck(payBox, param.getName());
            //更新
            payBox.setName(param.getName());
            payBox.setAppId(param.getPayApplicationAppId());
            payBox.setType(payApplicationDTO.getType());
            payBox.setMerchantNos(StringUtils.join(param.getMerchantNos(), ","));
            payBox.setStoreType(param.getStoreType());
            payBox.setRemark(param.getRemark());
            payBox.setUpdateTime(LocalDateTime.now());
            return super.updateById(payBox);
        }
        //判断名称是否已经存在
        this.payBoxNameCheck(null, param.getName());
        //创建
        return super.save(PayBox.builder()
                .name(param.getName())
                .appId(param.getPayApplicationAppId())
                .type(payApplicationDTO.getType())
                .merchantNos(StringUtils.join(param.getMerchantNos(), ","))
                .storeType(param.getStoreType())
                .remark(param.getRemark())
                .status(StatusEnum.YES.getCode())
                .isDelete(DeleteEnum.NO.getCode())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build());
    }

    private void payBoxNameCheck(PayBox payBox, String payBoxName) {
        //名字未更新, 不检查
        if (payBox != null && Objects.equals(payBox.getName(), payBoxName)) {
            return;
        }
        long count = super.count(new LambdaQueryWrapper<PayBox>().eq(PayBox::getName, payBoxName));
        if (count > 0) {
            throw new BaseException("支付盒子名称已经存在");
        }
    }

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

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

    @Override
    public PayBoxDTO getByPayBoxId(Long payBoxId) {
        PayBox payBox = super.getById(payBoxId);
        if (payBox == null) {
            return null;
        }
        return BeanUtil.copy(payBox, PayBoxDTO.class);
    }
}
