package com.ym.mec.biz.service.impl;

import com.alibaba.fastjson.JSON;
import com.huifu.adapay.model.payment.Payment;
import com.ym.mec.biz.dal.dao.StudentPaymentOrderDao;
import com.ym.mec.biz.dal.dto.PageInfoOrder;
import com.ym.mec.biz.dal.dto.SporadicChargeInfoDto;
import com.ym.mec.biz.dal.dto.StudentPaymentOrderExportDto;
import com.ym.mec.biz.dal.entity.Goods;
import com.ym.mec.biz.dal.entity.StudentPaymentOrder;
import com.ym.mec.biz.dal.enums.DealStatusEnum;
import com.ym.mec.biz.dal.enums.GroupType;
import com.ym.mec.biz.dal.enums.OrderDetailTypeEnum;
import com.ym.mec.biz.dal.enums.OrderTypeEnum;
import com.ym.mec.biz.dal.page.SporadicOrderQueryInfo;
import com.ym.mec.biz.dal.page.StudentPaymentOrderQueryInfo;
import com.ym.mec.biz.service.*;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.page.PageInfo;
import com.ym.mec.common.page.QueryInfo;
import com.ym.mec.common.service.impl.BaseServiceImpl;
import com.ym.mec.thirdparty.adapay.Pay;
import com.ym.mec.thirdparty.yqpay.Msg;
import com.ym.mec.thirdparty.yqpay.RsqMsg;
import com.ym.mec.thirdparty.yqpay.YqPayFeignService;
import com.ym.mec.thirdparty.yqpay.YqPayUtil;
import com.ym.mec.util.collection.MapUtil;

import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

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

@Service
public class StudentPaymentOrderServiceImpl extends BaseServiceImpl<Long, StudentPaymentOrder> implements StudentPaymentOrderService {

    @Autowired
    private StudentPaymentOrderDao studentPaymentOrderDao;
    @Autowired
    private YqPayFeignService yqPayFeignService;
    @Autowired
    private StudentRegistrationService studentRegistrationService;
    @Autowired
    @Lazy
    private VipGroupService vipGroupService;
    @Autowired
    private MusicGroupService musicGroupService;
    @Autowired
    private SporadicChargeInfoService sporadicChargeInfoService;
    @Autowired
    private PracticeGroupService practiceGroupService;

    @Override
    public BaseDAO<Long, StudentPaymentOrder> getDAO() {
        return studentPaymentOrderDao;
    }

    @Override
    public List<Goods> queryApplyGoodsList(String musicGroupId, OrderDetailTypeEnum type) {
        return studentPaymentOrderDao.queryApplyGoodsList(musicGroupId, type);
    }

    @Override
    public List<StudentPaymentOrder> queryByCondition(GroupType groupType, String musicGroupId, Integer userId, DealStatusEnum status, OrderTypeEnum type) {
        return studentPaymentOrderDao.queryByCondition(groupType, musicGroupId, userId, status, type);
    }

    @Override
    public StudentPaymentOrder findMusicGroupApplyOrderByStatus(Integer userId, String musicGroupId, DealStatusEnum status) {
        return studentPaymentOrderDao.findMusicGroupApplyOrderByStatus(userId, musicGroupId, status);
    }

    @Override
    public StudentPaymentOrder findOrderByOrderNo(String orderNo) {
        return studentPaymentOrderDao.findOrderByOrderNo(orderNo);
    }

    @Override
    public int findPayOrderNum() {
        return studentPaymentOrderDao.findPayOrderNum();
    }

    @Override
    public List<StudentPaymentOrder> findOrdersByStatus(DealStatusEnum status, String paymentChannel) {
        return studentPaymentOrderDao.findOrdersByStatus(status, paymentChannel);
    }

    @Override
    public List<StudentPaymentOrder> findOrdersOverTime(List<String> orderNoList, DealStatusEnum status, Date beforeTime) {
        return studentPaymentOrderDao.findOrdersOverTime(orderNoList, status, beforeTime);
    }

    @Override
    public void queryOrderStatus() throws Exception {
        yqPayQuery();
        adaPayQuery();
    }

    private void yqPayQuery() throws Exception {
        List<StudentPaymentOrder> payingOrders = findOrdersByStatus(DealStatusEnum.ING, "YQPAY");

        if (payingOrders.size() == 0) {
            return;
        }
        List<String> orderNoList = payingOrders.stream().map(StudentPaymentOrder::getOrderNo).collect(Collectors.toList());
        String merOrderNos = payingOrders.stream().map(StudentPaymentOrder::getOrderNo).collect(Collectors.joining(","));

        String notifyUrl = ""; //回调地址
        Map<String, Object> resultMap = new LinkedHashMap<>();
        resultMap.put("merOrderNoList", merOrderNos);
        Map<String, Object> requestMap = YqPayUtil.getRequestMap(notifyUrl, resultMap);

        RsqMsg rsqMsg = new RsqMsg(requestMap);

        Msg queryRs = yqPayFeignService.orderQuery(rsqMsg);

        if (queryRs.getCode().equals("88")) {
            //更新订单状态
            String[] statusArr = {"0", "1", "7"};
            String responseParameters = queryRs.getResponseParameters();
            List<Map<String, String>> responseList = JSON.parseObject(responseParameters, List.class);
            for (Map<String, String> response : responseList) {
                Map<String, String> rpMap = response;
                String channelType = rpMap.get("channelType").equals("1") ? "WXPay" : (rpMap.get("channelType").equals("2") ? "Alipay" : "quickPay");
                rpMap.put("channelType", channelType);

                if (orderNoList.contains(rpMap.get("merOrderNo"))) {
                    orderNoList.remove(rpMap.get("merOrderNo"));
                }

                if (Arrays.asList(statusArr).contains(rpMap.get("tradeState"))) {
                    try {
                        updateOrder(rpMap); //更新订单
                    } catch (Exception e) {
                        e.printStackTrace();
                        continue;
                    }
                }
            }
            closeOrders(orderNoList); //关闭订单
        }
    }

    private void adaPayQuery() throws Exception {
        List<StudentPaymentOrder> payingOrders = findOrdersByStatus(DealStatusEnum.ING, "ADAPAY");
        if (payingOrders.size() == 0) {
            return;
        }

        List<String> orderNoList = new ArrayList<String>();

        for (StudentPaymentOrder payingOrder : payingOrders) {
            if (payingOrder.getTransNo() == null) {
                orderNoList.add(payingOrder.getOrderNo());
                continue;
            }
            Payment payment = new Pay().queryPayment(payingOrder.getTransNo());
            Map<String, String> rpMap = new HashMap<>();
            rpMap.put("merOrderNo", payingOrder.getOrderNo());
            rpMap.put("remarks", payment.getReason());
            rpMap.put("orderNo", payment.getId());
            rpMap.put("channelType", payment.getPayChannel());
            if (payment.getStatus().equals("succeeded")) {
                rpMap.put("tradeState", "1");
            }
            if (payment.getStatus().equals("failed")) {
                rpMap.put("tradeState", "0");
            }
            if (payment.getStatus().equals("pending")) {
                orderNoList.add(payingOrder.getOrderNo());
            }
        }
        closeOrders(orderNoList);
    }

    public void updateOrder(Map<String, String> rpMap) throws Exception {
        DealStatusEnum status = rpMap.get("tradeState").equals("1") ? DealStatusEnum.SUCCESS : DealStatusEnum.FAILED;
        StudentPaymentOrder order = findOrderByOrderNo(rpMap.get("merOrderNo"));
        if (order == null || !order.getStatus().equals(DealStatusEnum.ING)) {
            return;
        }

        if (status.equals(DealStatusEnum.SUCCESS)) {
            order.setPayTime(new Date());
        } else {
            order.setMemo(rpMap.get("remarks"));
        }
        order.setStatus(status);
        order.setTransNo(rpMap.get("orderNo"));
        order.setPaymentBusinessChannel(rpMap.get("channelType"));

        if (order.getType().equals(OrderTypeEnum.APPLY)) { //报名订单
            studentRegistrationService.updateApplyOrder(order);
        } else if (order.getType().equals(OrderTypeEnum.SMALL_CLASS_TO_BUY)) {
            vipGroupService.orderCallback(order);
        } else if (order.getType().equals(OrderTypeEnum.RENEW)) {
            musicGroupService.renewForCallback(order);
        } else if (order.getType().equals(OrderTypeEnum.SPORADIC) || order.getType().equals(OrderTypeEnum.LUCK)) {
            sporadicChargeInfoService.renewForCallback(order);
        } else if (order.getType().equals(OrderTypeEnum.PRACTICE_GROUP_BUY) || order.getType().equals(OrderTypeEnum.PRACTICE_GROUP_RENEW)) {
            practiceGroupService.orderCallback(order);
        }
    }

    @Override
    public Integer findOrderByGroupType(Integer userId, Integer sporadicId, String sporadic, DealStatusEnum status) {
        return studentPaymentOrderDao.findOrderByGroupType(userId, sporadicId, sporadic, status);
    }


    private void closeOrders(List<String> orderNoList) throws Exception {
        if (orderNoList.size() == 0) {
            return;
        }

        Calendar beforeTime = Calendar.getInstance();
        beforeTime.add(Calendar.MINUTE, -30);// 30分钟之前的时间
        Date beforeDate = beforeTime.getTime();

        List<StudentPaymentOrder> ordersOverTime = findOrdersOverTime(orderNoList, DealStatusEnum.ING, beforeDate);
        for (StudentPaymentOrder order : ordersOverTime) {
            try {
                order.setStatus(DealStatusEnum.FAILED);
                order.setMemo("超时未支付关闭");
                if (order.getType().equals(OrderTypeEnum.APPLY)) { //报名订单
                    studentRegistrationService.updateApplyOrder(order);
                } else if (order.getType().equals(OrderTypeEnum.SMALL_CLASS_TO_BUY)) {
                    vipGroupService.orderCallback(order);
                } else if (order.getType().equals(OrderTypeEnum.RENEW)) {
                    musicGroupService.renewForCallback(order);
                } else if (order.getType().equals(OrderTypeEnum.SPORADIC) || order.getType().equals(OrderTypeEnum.LUCK)) {
                    sporadicChargeInfoService.renewForCallback(order);
                } else if (order.getType().equals(OrderTypeEnum.PRACTICE_GROUP_BUY) || order.getType().equals(OrderTypeEnum.PRACTICE_GROUP_RENEW)) {
                    practiceGroupService.orderCallback(order);
                }
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }

    }

    @Override
    public List<StudentPaymentOrderExportDto> ExportQueryPage(Map<String, Object> params) {
        return studentPaymentOrderDao.ExportQueryPage(params);
    }

    @Override
    public PageInfo<SporadicChargeInfoDto> sporadicQueryPage(SporadicOrderQueryInfo queryInfo) {
        PageInfo<SporadicChargeInfoDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);

        List<SporadicChargeInfoDto> dataList = null;
        int count = studentPaymentOrderDao.countSporadicPage(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = studentPaymentOrderDao.sporadicQueryPage(params);
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public StudentPaymentOrder getOrderMoneyAmount(StudentPaymentOrderQueryInfo queryInfo) {
        Map<String, Object> params = new HashMap<String, Object>();
        MapUtil.populateMap(params, queryInfo);
        return studentPaymentOrderDao.getOrderMoneyAmount(params);
    }

    @Override
    public PageInfoOrder<StudentPaymentOrder> OrderQueryPage(StudentPaymentOrderQueryInfo queryInfo) {
        PageInfoOrder<StudentPaymentOrder> pageInfo = new PageInfoOrder<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<String, Object>();
        MapUtil.populateMap(params, queryInfo);

        List<StudentPaymentOrder> dataList = new ArrayList<>();
        int count = this.findCount(params);
        StudentPaymentOrder orderMoneyAmount = studentPaymentOrderDao.getOrderMoneyAmount(params);
        if(orderMoneyAmount != null){
            BigDecimal totalExpectAmount = orderMoneyAmount.getExpectAmount() !=null? orderMoneyAmount.getExpectAmount():BigDecimal.ZERO;
            BigDecimal totalActualAmount = orderMoneyAmount.getActualAmount() !=null? orderMoneyAmount.getActualAmount():BigDecimal.ZERO;
            pageInfo.setTotalExpectAmount(totalExpectAmount);
            pageInfo.setTotalActualAmount(totalActualAmount);
        }
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = studentPaymentOrderDao.queryPageOrder(params);
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }
}
