package com.softwarebr.nunu.service.user.impl;

import com.brframework.commondb.core.AbstractEntityService;
import com.brframework.commondb.core.CommonRepository;
import com.brframework.commondistributed.annotation.DistributedLock;
import com.brframework.commonmq.annotation.MQConfig;
import com.brframework.commonmq.annotation.MQListener;
import com.brframework.commonmq.core.MQClient;
import com.brframework.commonweb.exception.HandleException;
import com.softwarebr.nunu.dao.user.OrderDao;
import com.softwarebr.nunu.domain.Calculation;
import com.softwarebr.nunu.domain.OrderOnlinePay;
import com.softwarebr.nunu.domain.WxPayOrder;
import com.softwarebr.nunu.entity.train.Activity;
import com.softwarebr.nunu.entity.user.Order;
import com.softwarebr.nunu.globals.MQTopics;
import com.softwarebr.nunu.service.train.ActivityLogService;
import com.softwarebr.nunu.service.train.ActivityService;
import com.softwarebr.nunu.service.user.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * @author lilin
 * @date 2020-02-27 12:00:43
 */

@Slf4j
@Service
@MQConfig
public class OrderServiceImpl extends AbstractEntityService<Order, Long, Object> implements OrderService {

    /**
     * 订单自动取消时间（分钟）
     */
    public final static Integer AUTO_CANCEL_MINUTES = 10;

    @Autowired
    private OrderDao orderDao;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private MQClient mqClient;

    @Autowired
    private ActivityLogService activityLogService;

    @Override
    public CommonRepository<Long, Order> getRepository() {
        return orderDao;
    }

    public OrderService getProxy() {
        if (AopContext.currentProxy() instanceof OrderService) {
            return (OrderService) AopContext.currentProxy();
        } else {
            return this;
        }
    }


    /**
     * 自动取消订单
     *
     * @param topic
     * @param message
     */
    @MQListener(topic = MQTopics.ORDER_AUTO_CANCEL)
    public void autoCancelListener(String topic, String message) {
        getProxy().cancelOrder(message);
    }

    @Override
    public Order accessObjectByOrderNo(String orderNo) {
        Order order = orderDao.findByOrderNo(orderNo);
        return order;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @DistributedLock(key = "'ORDER_HANDLE' + #orderNo")
    public void cancelOrder(String orderNo) {
        Order order = accessObjectByOrderNo(orderNo);
        if (!order.getOrderStatus().equals(Order.ORDER_STATUS_AWAITING)) {
            log.info("{}订单状态有误, 操作失败！", orderNo);
            return;
        }
        order.setOrderStatus(Order.ORDER_STATUS_CANCEL);
        save(order);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refundOrder(Long orderId, Integer orderStatus) {
        Order order = accessObject(orderId);
        if (!order.getOrderStatus().equals(Order.ORDER_STATUS_REFUNDING)) {
            log.info("{}订单状态不支持退款处理，操作失败！", order.getOrderNo());
            return;
        }
        if (orderStatus.equals(Order.ORDER_STATUS_REFUNDED)) {
            //更新报名人数
            activityService.activityEnrolment(order.getActivityId(), -order.getOrderAmount());
            //入场码失效
            activityLogService.failureStatusUpdate(order.getOrderNo());
        }
        order.setOrderStatus(orderStatus);
        save(order);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @DistributedLock(key = "'ORDER_HANDLE' + #orderNo")
    public Order confirmOrder(Long memberId, String orderNo, Long activityId, Integer orderAmount) {
        Order order = accessObjectByOrderNo(orderNo);
        if (null != order) {
            throw new HandleException("订单已存在，请勿重复下单！");
        }
        Calculation calculation = calculationOrder(activityId, orderAmount);
        order = new Order();
        order.setOrderNo(orderNo);
        order.setActivityId(activityId);
        order.setOrderAmount(orderAmount);
        order.setMemberId(memberId);
        order.setPrice(calculation.getPrice());
        order.setTotalPrice(calculation.getTotalPrice());
        order.setCreateDate(LocalDateTime.now());
        order.setOrderStatus(Order.ORDER_STATUS_AWAITING);
        order.setAutoCancelDate(LocalDateTime.now().plusMinutes(AUTO_CANCEL_MINUTES));
        order = save(order);
        Activity activity = activityService.accessObject(order.getActivityId());
        mqClient.publish(MQTopics.ORDER_AUTO_CANCEL, order.getOrderNo(), order.getAutoCancelDate());
        mqClient.publish(MQTopics.ORDER_AUTO_CANCEL, order.getOrderNo(), activity.getSignEndDate());
        return order;
    }

    @Override
    public Calculation calculationOrder(Long activityId, Integer orderAmount) {
        if (orderAmount <= 0) {
            throw new HandleException("订单信息有误，请检查是否选择订票数量！");
        }
        Activity activity = activityService.accessObject(activityId);
        Calculation calculationResult = new Calculation();
        calculationResult.setOrderAmount(orderAmount);
        calculationResult.setTotalPrice(activity.getPrice().multiply(new BigDecimal(orderAmount)));
        calculationResult.setPrice(activity.getPrice());
        return calculationResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @DistributedLock(key = "'ORDER_HANDLE' + #orderNo")
    public OrderOnlinePay onlinePayOrder(String orderNo, Integer payType) {
        Order order = accessObjectByOrderNo(orderNo);
        if (null == payType) {
            throw new HandleException("请选择支付方式");
        }
        if (order.getOrderStatus().equals(Order.ORDER_STATUS_CANCEL)) {
            throw new HandleException("订单已取消，支付失败");
        }
        if (order.getOrderStatus().equals(Order.ORDER_STATUS_RECEIVED)) {
            throw new HandleException("订单已付款，请勿重复支付");
        }
        OrderOnlinePay onlinePay = new OrderOnlinePay();
        order.setPayType(payType);
        save(order);
        onlinePay.setPayMethod(payType);
        return onlinePay;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @DistributedLock(key = "'ORDER_HANDLE' + #orderNo")
    public void onlinePaySuccess(String orderNo) {
        Order order = accessObjectByOrderNo(orderNo);
        if (!order.getOrderStatus().equals(Order.ORDER_STATUS_AWAITING)) {
            log.info("{}订单状态有误，支付失败！", orderNo);
            return;
        }
        order.setOrderStatus(Order.ORDER_STATUS_RECEIVED);
        save(order);
        activityService.activityEnrolment(order.getActivityId(), order.getOrderAmount());
        activityLogService.enrolmentUpdate(orderNo, order.getOrderAmount());
        activityLogService.voucherCodeUpdate(orderNo);
    }

}