package com.tmerclub.cloud.order.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.tmerclub.cloud.api.multishop.feign.ShopDetailFeignClient;
import com.tmerclub.cloud.api.multishop.vo.ShopDetailVO;
import com.tmerclub.cloud.api.user.dto.FinanceDetailDTO;
import com.tmerclub.cloud.api.user.feign.UserBalanceLogFeignClient;
import com.tmerclub.cloud.api.user.feign.UserFeignClient;
import com.tmerclub.cloud.api.user.feign.UserLevelLogFeignClient;
import com.tmerclub.cloud.api.user.vo.FinanceDetailExcelVO;
import com.tmerclub.cloud.api.user.vo.FinanceDetailVO;
import com.tmerclub.cloud.api.user.vo.UserApiVO;
import com.tmerclub.cloud.common.constant.PayType;
import com.tmerclub.cloud.common.database.dto.PageDTO;
import com.tmerclub.cloud.common.database.vo.PageVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.common.util.PriceUtil;
import com.tmerclub.cloud.order.constant.Constant;
import com.tmerclub.cloud.order.constant.FinanceBizType;
import com.tmerclub.cloud.order.manager.MongoOrderManager;
import com.tmerclub.cloud.order.manager.MongoOrderRefundManager;
import com.tmerclub.cloud.order.service.OrderFinanceService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单财务
 *
 * @author TRACK
 */
@Service
public class OrderFinanceServiceImpl implements OrderFinanceService {

    @Autowired
    private MongoOrderRefundManager mongoOrderRefundManager;
    @DubboReference
    private UserBalanceLogFeignClient userBalanceLogFeignClient;
    @DubboReference
    private UserLevelLogFeignClient userLevelLogFeignClient;
    @DubboReference
    private UserFeignClient userFeignClient;
    @DubboReference
    private ShopDetailFeignClient shopDetailFeignClient;
    @Autowired
    private MongoOrderManager mongoOrderManager;

    @Override
    public PageVO<FinanceDetailVO> pageFinanceDetail(PageDTO pageDTO, FinanceDetailDTO financeDetailDTO) {
        financeDetailDTO.setPageSize(pageDTO.getPageSize());
        financeDetailDTO.setPageNum(pageDTO.getPageNum());
        PageVO<FinanceDetailVO> result = new PageVO<>();
        if (Objects.equals(financeDetailDTO.getFinanceBizType(), FinanceBizType.ORDER.value())) {
            result = mongoOrderManager.pageOrderFinanceDetail(pageDTO, financeDetailDTO);
        } else if (Objects.equals(financeDetailDTO.getFinanceBizType(), FinanceBizType.REFUND.value())) {
            result = mongoOrderRefundManager.pageRefundFinanceDetail(pageDTO, financeDetailDTO);
        } else if (Objects.equals(financeDetailDTO.getFinanceBizType(), FinanceBizType.RECHARGE.value())) {
            ServerResponseEntity<PageVO<FinanceDetailVO>> balanceResponse = userBalanceLogFeignClient.pageFinanceDetail(financeDetailDTO);
            if (!balanceResponse.isSuccess()) {
                throw new LuckException(balanceResponse.getMsg());
            }
            result = balanceResponse.getData();
        } else if (Objects.equals(financeDetailDTO.getFinanceBizType(), FinanceBizType.LEVEL.value())) {
            ServerResponseEntity<PageVO<FinanceDetailVO>> levelResponse = userLevelLogFeignClient.pageFinanceDetail(financeDetailDTO);
            if (!levelResponse.isSuccess()) {
                throw new LuckException(levelResponse.getMsg());
            }
            result = levelResponse.getData();
        }
        if (CollUtil.isNotEmpty(result.getList())) {
            List<Long> userIds = new ArrayList<>(Constant.INITIAL_CAPACITY);
            Set<Long> shopIds = new HashSet<>(Constant.INITIAL_CAPACITY);
            for (FinanceDetailVO financeDetailVO : result.getList()) {
                userIds.add(financeDetailVO.getUserId());
                shopIds.add(financeDetailVO.getShopId());
            }
            // 查询用户信息
            ServerResponseEntity<List<UserApiVO>> userResponse = userFeignClient.getUserByUserIds(userIds);
            if (!userResponse.isSuccess()) {
                throw new LuckException(userResponse.getMsg());
            }
            List<UserApiVO> userResponseData = userResponse.getData();
            Map<Long, String> userMap = userResponseData.stream().collect(Collectors.toMap(UserApiVO::getUserId, UserApiVO::getNickName));
            // 查询店铺信息
            List<ShopDetailVO> shops = shopDetailFeignClient.listByShopIds(new ArrayList<>(shopIds)).getData();
            Map<Long, String> shopNameMap = new HashMap<>(Constant.INITIAL_CAPACITY);
            if (!CollectionUtils.isEmpty(shops)) {
                shopNameMap = shops.stream().collect(Collectors.toMap(ShopDetailVO::getShopId, ShopDetailVO::getShopName));
            }
            // 补充信息
            String shopName;
            for (FinanceDetailVO financeDetailVO : result.getList()) {
                String userName = userMap.get(financeDetailVO.getUserId());
                financeDetailVO.setUserName(Objects.isNull(userName) ? "用户已注销" : userName);
                if (!ObjectUtils.isEmpty(shopName = shopNameMap.get(financeDetailVO.getShopId()))) {
                    financeDetailVO.setShopName(shopName);
                }
            }
        }
        return result;
    }

    @Override
    public List<FinanceDetailExcelVO> listExcelFinanceDetail(FinanceDetailDTO financeDetailDTO) {
        List<FinanceDetailVO> listFinanceDetail = mongoOrderManager.listOrderFinanceDetail(financeDetailDTO);
        List<FinanceDetailVO> listRefundFinanceDetail = mongoOrderRefundManager.listRefundFinanceDetail(financeDetailDTO);
        if (CollUtil.isNotEmpty(listRefundFinanceDetail)) {
            listFinanceDetail.addAll(listRefundFinanceDetail);
        }
        List<FinanceDetailExcelVO> financeDetailExcelList = BeanUtil.mapAsList(listFinanceDetail, FinanceDetailExcelVO.class);
        ServerResponseEntity<List<FinanceDetailExcelVO>> balanceResponse = userBalanceLogFeignClient.listFinanceDetail(financeDetailDTO);
        if (!balanceResponse.isSuccess()) {
            throw new LuckException(balanceResponse.getMsg());
        }
        if (CollUtil.isNotEmpty(balanceResponse.getData())) {
            financeDetailExcelList.addAll(balanceResponse.getData());
        }
        ServerResponseEntity<List<FinanceDetailExcelVO>> levelResponse = userLevelLogFeignClient.listFinanceDetail(financeDetailDTO);
        if (!levelResponse.isSuccess()) {
            throw new LuckException(levelResponse.getMsg());
        }
        if (CollUtil.isNotEmpty(levelResponse.getData())) {
            financeDetailExcelList.addAll(levelResponse.getData());
        }
        if (CollUtil.isNotEmpty(financeDetailExcelList)) {
            financeDetailExcelList = financeDetailExcelList.stream().sorted(Comparator.comparing(FinanceDetailExcelVO::getTransDate).reversed()).collect(Collectors.toList());
            List<Long> userIds = financeDetailExcelList.stream().map(FinanceDetailExcelVO::getUserId).collect(Collectors.toList());
            ServerResponseEntity<List<UserApiVO>> userResponse = userFeignClient.getUserByUserIds(userIds);
            if (!userResponse.isSuccess()) {
                throw new LuckException(userResponse.getMsg());
            }
            Map<Long, String> userMap = userResponse.getData().stream().collect(Collectors.toMap(UserApiVO::getUserId, UserApiVO::getNickName));
            for (FinanceDetailExcelVO financeDetailVO : financeDetailExcelList) {
                String userName = userMap.get(financeDetailVO.getUserId());
                financeDetailVO.setUserName(Objects.isNull(userName) ? "用户已注销" : userName);
                financeDetailVO.setBizTypeStr(Objects.requireNonNull(FinanceBizType.instance(financeDetailVO.getBizType())).str());
                financeDetailVO.setPayTypeName(PayType.getPayTypeName(financeDetailVO.getPayType()));
                financeDetailVO.setAmount(PriceUtil.toDecimalPrice(financeDetailVO.getTransAmount()).toString());
            }
        }
        return financeDetailExcelList;
    }
}
