package com.keao.edu.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.keao.edu.common.dal.BaseDAO;
import com.keao.edu.common.exception.BizException;
import com.keao.edu.common.page.PageInfo;
import com.keao.edu.common.service.impl.BaseServiceImpl;
import com.keao.edu.thirdparty.adapay.Payment;
import com.keao.edu.thirdparty.yqpay.Msg;
import com.keao.edu.thirdparty.yqpay.RsqMsg;
import com.keao.edu.thirdparty.yqpay.YqPayFeignService;
import com.keao.edu.thirdparty.yqpay.YqPayUtil;
import com.keao.edu.user.dao.ExamOrganizationRelationDao;
import com.keao.edu.user.dao.ExamRegistrationPaymentDao;
import com.keao.edu.user.dto.ExamPaymentInfo;
import com.keao.edu.user.dto.ExamRegistrationDto;
import com.keao.edu.user.dto.ExamRegistrationPaymentDto;
import com.keao.edu.user.entity.ExamOrganizationRelation;
import com.keao.edu.user.entity.ExamRegistration;
import com.keao.edu.user.entity.ExamRegistrationPayment;
import com.keao.edu.user.entity.Organization;
import com.keao.edu.user.enums.StudentRegistrationStatusEnum;
import com.keao.edu.user.enums.TransStatusEnum;
import com.keao.edu.user.page.ExamRegistrationPaymentQueryInfo;
import com.keao.edu.user.service.ExamRegistrationPaymentService;
import com.keao.edu.user.service.ExamRegistrationService;
import com.keao.edu.user.service.OrganizationService;
import com.keao.edu.util.collection.MapUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

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

@Service
public class ExamRegistrationPaymentServiceImpl extends BaseServiceImpl<Long, ExamRegistrationPayment> implements ExamRegistrationPaymentService {

    @Autowired
    private ExamRegistrationPaymentDao examRegistrationPaymentDao;
    @Autowired
    private ExamRegistrationService examRegistrationService;
    @Autowired
    private YqPayFeignService yqPayFeignService;
    @Autowired
    private OrganizationService organizationService;
    @Autowired
    private ExamOrganizationRelationDao examOrganizationRelationDao;

    @Override
    public BaseDAO<Long, ExamRegistrationPayment> getDAO() {
        return examRegistrationPaymentDao;
    }

    @Override
    public ExamRegistrationPayment getExamIngOrder(Long examinationBasicId, Integer userId) {
        return examRegistrationPaymentDao.getExamIngOrder(examinationBasicId, userId);
    }

    @Override
    public ExamRegistrationPayment getByOrderNo(String orderNo) {
        return examRegistrationPaymentDao.getByOrderNo(orderNo);
    }

    @Override
    public ExamPaymentInfo getExamOrderInfo(String orderNo) {
        ExamPaymentInfo examPaymentInfo = new ExamPaymentInfo();
        ExamRegistrationPayment order = examRegistrationPaymentDao.getByOrderNo(orderNo);
        ExamRegistrationDto examRegistration = examRegistrationService.getExamRegistration(order.getExamRegistrationId());
        examPaymentInfo.setExamRegistrationPayment(order);
        examPaymentInfo.setExamRegistrationDto(examRegistration);
        return examPaymentInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
    public ExamRegistrationPayment updateOrder(Map<String, String> rpMap) {
        ExamRegistrationPayment order = examRegistrationPaymentDao.getByOrderNo(rpMap.get("orderNo"));
        if (order == null || !order.getTransStatus().equals(TransStatusEnum.ING)) {
            return order;
        }
        TransStatusEnum status = rpMap.get("transStatus").equals("SUCCESS") ? TransStatusEnum.SUCCESS : TransStatusEnum.FAILED;


        if (status.equals(TransStatusEnum.SUCCESS)) {
            order.setTransSuccessedTime(new Date());
        } else {
            order.setMemo(rpMap.get("memo"));
        }
        order.setTransStatus(status);
        order.setTransNo(rpMap.get("transNo"));
        order.setPayChannel(rpMap.get("channelType"));

        if (examRegistrationPaymentDao.update(order) <= 0) {
            throw new BizException("订单更新失败");
        }
        ExamRegistration examRegistration = examRegistrationService.get(order.getExamRegistrationId());
        if (!examRegistration.getStatus().equals(StudentRegistrationStatusEnum.PAY_WAIT)) {
            return order;
        }

        StudentRegistrationStatusEnum registrationStatus = order.getTransStatus().equals(TransStatusEnum.SUCCESS) ? StudentRegistrationStatusEnum.AUDIT_WAIT : StudentRegistrationStatusEnum.CANCEL;
        examRegistration.setStatus(registrationStatus);
        examRegistration.setUpdateTime(new Date());
        if (examRegistrationService.update(examRegistration) <= 0) {
            throw new BizException("报名状态更新失败");
        }
        if (!order.getTransStatus().equals(TransStatusEnum.SUCCESS)) {
            return order;
        }
        //更新报名人数，和报名金额
        ExamOrganizationRelation examOrganizationRelation = examOrganizationRelationDao.getExamOrganizationRelation(examRegistration.getExaminationBasicId(), examRegistration.getOrganId());
        int selfRegistrationStudentNum = examOrganizationRelation.getSelfRegistrationStudentNum() == null ? 0 : examOrganizationRelation.getSelfRegistrationStudentNum();
        examOrganizationRelation.setSelfRegistrationStudentNum(selfRegistrationStudentNum + 1);
        BigDecimal selfPaymentAmount = examOrganizationRelation.getSelfPaymentAmount() == null ? BigDecimal.ZERO : examOrganizationRelation.getSelfPaymentAmount();
        BigDecimal amount = selfPaymentAmount.add(examRegistration.getLevelFee()).add(examRegistration.getTheoryLevelFee());
        examOrganizationRelation.setSelfPaymentAmount(amount);
        if (examOrganizationRelationDao.update(examOrganizationRelation) <= 0) {
            throw new BizException("报名人数报名金额更新失败");
        }
        Organization organization = organizationService.get(examRegistration.getOrganId());

        List<Integer> parentOrganIds = Arrays.stream(organization.getParentOrganIdTag().split(","))
                .map(e -> Integer.valueOf(e)).collect(Collectors.toList());
        List<ExamOrganizationRelation> examOrgans = examOrganizationRelationDao.getExamOrganizationRelations(examRegistration.getExaminationBasicId(), parentOrganIds);
        for (ExamOrganizationRelation examOrgan : examOrgans) {
            examOrgan.setTotalRegistrationStudentNum(examOrgan.getTotalRegistrationStudentNum() + 1);
            BigDecimal totalAmount = examOrgan.getTotalPaymentAmount().add(examRegistration.getLevelFee()).add(examRegistration.getTheoryLevelFee());
            examOrgan.setTotalPaymentAmount(totalAmount);
        }
        if(!CollectionUtils.isEmpty(examOrgans)){
            examOrganizationRelationDao.batchUpdate(examOrgans);
        }

        return order;
    }

    @Override
    public PageInfo<ExamRegistrationPaymentDto> pageList(ExamRegistrationPaymentQueryInfo queryInfo) {
        PageInfo<ExamRegistrationPaymentDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());

        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);

        List<Integer> nextLevelOrganIds = organizationService.getChildOrganIds(queryInfo.getOrganId(), true);
        params.put("organIds", nextLevelOrganIds);

        List<ExamRegistrationPaymentDto> dataList = Collections.EMPTY_LIST;
        int count = examRegistrationPaymentDao.getOrderListCount(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = examRegistrationPaymentDao.getOrderPageList(params);
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean closeOrder(String orderNo) {
        ExamRegistrationPayment order = examRegistrationPaymentDao.getByOrderNo(orderNo);
        if (!order.getTransStatus().equals(TransStatusEnum.ING)) {
            throw new BizException("订单不是待支付状态,不能关闭");
        }
        Date nowDate = new Date();
        order.setMemo("用户主动放弃支付");
        order.setTransStatus(TransStatusEnum.CLOSE);
        order.setUpdateTime(nowDate);
        if (examRegistrationPaymentDao.update(order) <= 0) {
            throw new BizException("订单关闭失败，请重试");
        }

        ExamRegistration examRegistration = examRegistrationService.get(order.getExamRegistrationId());
        examRegistration.setStatus(StudentRegistrationStatusEnum.CANCEL);
        examRegistration.setUpdateTime(nowDate);
        if (examRegistrationService.update(examRegistration) <= 0) {
            throw new BizException("报名取消失败，请重试");
        }
        return true;
    }


    private void yqPayQuery() throws Exception {
        List<ExamRegistrationPayment> orders = examRegistrationPaymentDao.getOrdersByStatus("ING", "YQPAY");
        if (orders.size() == 0) {
            return;
        }
        List<String> orderNoList = orders.stream().map(ExamRegistrationPayment::getOrderNo).collect(Collectors.toList());
        String merOrderNos = orders.stream().map(ExamRegistrationPayment::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");
                TransStatusEnum status = rpMap.get("tradeState").equals("1") ? TransStatusEnum.SUCCESS : TransStatusEnum.FAILED;
                String memo = rpMap.get("remarks");
                String orderNo = rpMap.get("merOrderNo");
                String transNo = rpMap.get("orderNo");

                rpMap.put("channelType", channelType);
                rpMap.put("memo", memo);
                rpMap.put("transStatus", status.getCode());
                rpMap.put("orderNo", orderNo);
                rpMap.put("transNo", transNo);

                if (orderNoList.contains(orderNo)) {
                    orderNoList.remove(orderNo);
                }

                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<ExamRegistrationPayment> orders = examRegistrationPaymentDao.getOrdersByStatus("ING", "ADAPAY");
        if (orders.size() == 0) {
            return;
        }

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

        for (ExamRegistrationPayment order : orders) {
            if (order.getTransNo() == null) {
                orderNoList.add(order.getOrderNo());
                continue;
            }
            Map<String, Object> payment = Payment.queryPayment(order.getTransNo());
            Map<String, String> rpMap = new HashMap<>();
            rpMap.put("orderNo", order.getOrderNo());
            rpMap.put("transNo", order.getTransNo());
            rpMap.put("channelType", (String) payment.get("pay_channel"));
            String status = (String) payment.get("status");
            if (payment.containsKey("error_msg")) {
                rpMap.put("memo", (String) payment.get("error_msg"));
            }
            if (status.equals("succeeded")) {
                rpMap.put("transStatus", "SUCCESS");
            }
            if (status.equals("failed")) {
                rpMap.put("transStatus", "FAILED");
            }

            if (rpMap.containsKey("transStatus")) {
                try {
                    updateOrder(rpMap); //更新订单
                } catch (Exception e) {
                    e.printStackTrace();
                    continue;
                }
            }

            if (status.equals("pending")) {
                orderNoList.add(order.getOrderNo());
            }
        }
        closeOrders(orderNoList);
    }


    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<ExamRegistrationPayment> ordersOverTime = examRegistrationPaymentDao.findOrdersOverTime(orderNoList, TransStatusEnum.ING, beforeDate);
        for (ExamRegistrationPayment order : ordersOverTime) {
            try {
                Map<String, String> rpMap = new HashMap<>();
                rpMap.put("orderNo", order.getOrderNo());
                rpMap.put("transNo", order.getTransNo());
                rpMap.put("memo", "超时未支付关闭");
                rpMap.put("transStatus", "FAILED");
                updateOrder(rpMap); //更新订单
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }

    }
}
