package com.iformall.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.common.ErrorCode;
import com.iformall.common.IdWorker;
import com.iformall.common.Result;
import com.iformall.common.ResultData;
import com.iformall.domain.po.*;
import com.iformall.domain.vo.WxOrderGroupMarketing;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.*;
import com.iformall.service.WxOrderGroupService;
import com.iformall.service.WxOrderService;
import com.iformall.service.WxRefundOrderService;
import com.iformall.utils.DateUtils;
import com.iformall.utils.RedisLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * @author gongbiao
 */
@Service
public class WxOrderGroupServiceImpl implements WxOrderGroupService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final Long notOrderGroupId = 0L;
    private final int endPeople = 0;

    @Autowired
    WxOrderGroupMapper wxOrderGroupMapper;

    @Autowired
    WxOrderMapper wxOrderMapper;

    @Autowired
    WxOrderService wxOrderService;

    @Autowired
    WxCUserMapper wxCUserMapper;

    @Autowired
    WxCouponMapper wxCouponMapper;

    @Autowired
    WxMallMapper wxMallMapper;

    @Autowired
    WxAppinfoMapper wxAppinfoMapper;

    @Autowired
    WxRefundOrderService wxRefundOrderService;

    @Autowired
    RedisLock redisLock;

    @Autowired
    WxCouponChannelMapper wxCouponChannelMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public void createOrderGroup(WxOrder order, WxCoupon wxCoupon) {
        Long orderGroupId = order.getOrderGroupId();
        //查看是否首次拼团，orderGroupId不等于0代表不是首次拼团，因为第二个加入的拼团者肯定有团单号
        if (!orderGroupId.equals(notOrderGroupId)) {
            // 非首次拼团
            // 参与拼团
            WxOrderGroup wxOrderGroup = wxOrderGroupMapper.selectById(orderGroupId);
            if(wxOrderGroup.getRemainPeople() < endPeople + 1) {
                logger.info(">>>>>>>>>>>>参团失败 修改订单状态后定时退款 团单号" + orderGroupId);
                throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_FAILD);
            }
            Integer remainPeople = wxOrderGroup.getRemainPeople()-1;
            wxOrderGroup.setStatus(remainPeople == endPeople ? EnumOrderStatus.ORDER_STATUS_COOPERATING_COMPLETE.getCode() : wxOrderGroup.getStatus());
            wxOrderGroup.setUpdateDate(new Date());
            logger.info("非首次拼团,更新拼团信息, 剩余人数-1");
            int row = wxOrderGroupMapper.updateOrderGroup(wxOrderGroup);
            if (row != 1) {
                logger.info(">>>>>>>>>>>>参团失败 修改订单状态后定时退款 团单号" + orderGroupId);
                throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_FAILD);
            }

            // 更新订单信息
            order.setOrderStatus(wxOrderGroup.getStatus());
            order.setPressEndDate(wxOrderGroup.getExpiredDate());
            order.setOrderGroupId(wxOrderGroup.getId());
            try {
                wxOrderMapper.updateById(order);
            } catch (Exception e) {
                logger.error("更新订单信息失败", e);
                throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_FAILD);
            }
            if (remainPeople == endPeople) {
                actionAfterOrderGroupSuccess(order, orderGroupId);
            }
        } else {
            logger.info("首次拼团，创建拼团信息");
            WxOrderGroup wxOrderGroup = new WxOrderGroup();
            final IdWorker idWorker = IdWorker.get();
            long groupId = idWorker.nextId();
            wxOrderGroup.setId(groupId);
            wxOrderGroup.setTenantId(order.getTenantId());
            wxOrderGroup.setOrderId(order.getId());
            wxOrderGroup.setCouponId(wxCoupon.getId());
            wxOrderGroup.setRemainPeople(wxCoupon.getPressLimitNum() - 1);
            wxOrderGroup.setUserId(order.getCUserId());
            Date date = new Date();
            wxOrderGroup.setCreateDate(date);
            wxOrderGroup.setUpdateDate(date);
            wxOrderGroup.setStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING.getCode());
            Date expiredDate = DateUtils.getHourTimeAfter(wxCoupon.getPressLimitHours(), new Date());
            if (expiredDate.after(wxCoupon.getValidEndDate())) {
                expiredDate = wxCoupon.getValidEndDate();
            }
            wxOrderGroup.setExpiredDate(expiredDate);
            try {
                wxOrderGroupMapper.insert(wxOrderGroup);
            } catch (Exception e) {
                logger.error("创建拼团信息失败", e);
                throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_FAILD);
            }
            //更新order
            order.setOrderStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING.getCode());
            order.setPressEndDate(expiredDate);
            order.setOrderGroupId(groupId);
            try {
                wxOrderMapper.updateById(order);
            } catch (Exception e) {
                logger.error("更新订单信息失败", e);
                throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_FAILD);
            }
        }

    }

    /**
     * 拼团成功后，完成拼团相关工作
     * @param order
     * @param orderGroupId
     */
    private void actionAfterOrderGroupSuccess(WxOrder order, Long orderGroupId) {
        // 拼团完成
        //  得到所有拼团的order
        WxOrder wxOrder = new WxOrder();
        wxOrder.setTenantId(order.getTenantId());
        wxOrder.setOrderGroupId(orderGroupId);
        List<WxOrder> list = wxOrderMapper.findList(wxOrder).parallelStream()
                .filter(o -> {
                    return o.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING.getCode()) ||
                            o.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING_COMPLETE.getCode());
                }).collect(Collectors.toList());
        //   已成功订单，用户领取couponOrder
        for (WxOrder temp : list) {
            // 下订单成功
            try {
                wxOrderService.couponOrderSuccess(temp);
            } catch (Exception e) {
                logger.error("创建COUPON_ORDER失败", e);
                throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_FAILD);
            }
            // 下订单完成，发送内部消息
            try {
                wxOrderService.sendOrderSuccessActionMsg(temp);
            } catch (Exception e) {
                logger.error("内部消息发送失败: " + e.getMessage());
            }
        }
        //   拼团成功后，取消待支付订单
        wxOrder.setOrderStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING_UNPAID.getCode());
        list = wxOrderMapper.selectList(new QueryWrapper(wxOrder));
        for (WxOrder temp : list) {
            //去库存
            wxOrderService.updateOrderStatus(temp);
            //拼团取消
            temp.setOrderStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING_BREAK.getCode());
            wxOrderMapper.updateById(temp);
        }
    }

    @Override
    public ResultData queryRemainOne(WxOrderGroup wxOrderGroup, Long userId) {
        //取过期时间最大的数据
        List<WxOrderGroup> list = wxOrderGroupMapper.selectList(new QueryWrapper(wxOrderGroup));
        WxOrderGroup group = list.parallelStream()
                .filter(o -> !o.getUserId().equals(userId) && o.getExpiredDate().after(new Date()))
                .max(Comparator.comparing(WxOrderGroup::getExpiredDate))
                .orElse(null);
        if (group == null) {
            return new ResultData(Result.SUCCESS, "查询成功", group);
        }
        Map<String, Object> result = wxOrderGroupMapper.queryRemainOne(group);
        return new ResultData(Result.SUCCESS, "查询成功", result);
    }

    @Override
    public PageInfo<Map<String, Object>> queryOrderGroup(WxOrder wxOrder, Integer pageIndex, Integer pageSize) {
        PageHelper.startPage(pageIndex, pageSize);
        List<Map<String, Object>> result = wxOrderGroupMapper.queryOrderGroup(wxOrder);
        //更新状态
        logger.info("更新状态:" + result);
        updateOrderGroupStatus(result);
        PageHelper.startPage(pageIndex, pageSize);
        result = wxOrderGroupMapper.queryOrderGroup(wxOrder);
        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(result);
        return pageInfo;
    }

    private void updateOrderGroupStatus(List<Map<String, Object>> result) {
        for (Map<String, Object> group : result) {
            WxOrderGroup wxOrderGroup = new WxOrderGroup();
            wxOrderGroup.setId((Long) group.get("orderGroupId"));
            wxOrderGroup.setTenantId(group.get("tenantId").toString());
            wxOrderGroup.setCouponId((Long) group.get("couponId"));
            wxOrderGroup.setOrderId((Long) group.get("orderId"));
            updateGroupStatus(wxOrderGroup);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public ResultData toOrderGroup(WxOrderGroup wxOrderGroup) {
        WxOrder orderTemp = wxOrderMapper.selectById(wxOrderGroup.getOrderId());
        if (orderTemp == null) {
            return new ResultData(ErrorCode.ORDER_IS_NOT_FIND);
        }
        if (orderTemp.getOrderGroupId().equals(notOrderGroupId)) {
            return new ResultData(ErrorCode.ORDER_GROUP_COOPERATING_FAILD);
        }
        WxCouponChannel wxCouponChannel = wxCouponChannelMapper.selectById(orderTemp.getCouponChannelId());
        if (wxCouponChannel.getStatus().equals(EnumCouponChannelStatus.STATUS_TAKE_OFFF.getCode())) {
            return new ResultData(ErrorCode.COUPON_CHANNEL_IS_TAKE_OFF);
        }
        WxOrder wxOrder = new WxOrder();
        wxOrder.setTenantId(wxOrderGroup.getTenantId());
        wxOrder.setId(wxOrderGroup.getOrderId());
        List<Map<String, Object>> couponOrderGroupList = wxOrderGroupMapper.queryOrderGroup(wxOrder);
        if (couponOrderGroupList.isEmpty()) {
            return new ResultData(ErrorCode.ORDER_GROUP_COOPERATING_FAILD);
        }
        Map<String, Object> couponOrderGroup = couponOrderGroupList.get(0);
        //商场地址
        WxMall wxMall = new WxMall();
        wxMall.setTenantId(wxOrderGroup.getTenantId());
        List<WxMall> list = wxMallMapper.findList(wxMall);
        if (!list.isEmpty()) {
            couponOrderGroup.put("addr", list.get(0).getAddr());
        }
        //参团人员
        wxOrder = new WxOrder();
        wxOrder.setOrderGroupId(wxOrderGroup.getId());
        wxOrder.setTenantId(wxOrderGroup.getTenantId());
        List<WxOrder> orderList = wxOrderMapper.selectList(new QueryWrapper(wxOrder));
        orderList = orderList.parallelStream().filter(o -> {
            return o.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING.getCode()) ||
                    o.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING_COMPLETE.getCode()) ||
                    o.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING_OVERTIME.getCode()) ||
                    o.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING_CANCEL.getCode());
        }).sorted(Comparator.comparing(order -> order.getId())).collect(Collectors.toList());
        if (!orderList.isEmpty()) {
            List<WxCUser> userList = new ArrayList<>();
            for (WxOrder order : orderList) {
                WxCUser user = wxCUserMapper.selectById(order.getCUserId());
                if (user != null) {
                    userList.add(user);
                }
            }
            if (!userList.isEmpty()) {
                userList = userList.parallelStream().map(u -> {
                    WxCUser temp = new WxCUser();
                    temp.setId(u.getId());
                    temp.setNickName(u.getNickName());
                    temp.setAvatarUrl(u.getAvatarUrl());
                    return temp;
                }).collect(Collectors.toList());
            }
            couponOrderGroup.put("userList", userList);
        }
        return new ResultData(couponOrderGroup);
    }

    @Override
    public ResultData queryOrderGroupStatus(WxOrderGroup wxOrderGroup) {
        updateGroupStatus(wxOrderGroup);
        return toOrderGroup(wxOrderGroup);
    }

    @Override
    public ResultData queryAttendStatus(WxOrderGroup wxOrderGroup) {
        WxOrder order = new WxOrder();
        order.setTenantId(wxOrderGroup.getTenantId());
        order.setCUserId(wxOrderGroup.getUserId());
        order.setOrderGroupId(wxOrderGroup.getId());
        List<WxOrder> list = wxOrderMapper.selectList(new QueryWrapper(order));
        long count = list.parallelStream().filter(o -> {
            return o.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING.getCode()) ||
                    o.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING_COMPLETE.getCode());
        }).count();
        WxOrderGroup group = wxOrderGroupMapper.selectById(wxOrderGroup.getId());
        Map<String, Object> result = new HashMap<>(2);
        result.put("attend", count > 0 ? true : false);
        result.put("status", group.getStatus());
        return new ResultData(result);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    @Override
    public void updateGroupStatus(WxOrderGroup wxOrderGroup) {
        Long id = wxOrderGroup.getId();
        WxOrderGroup group = wxOrderGroupMapper.selectById(id);
        if (group != null && group.getStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING.getCode())) {
            WxCoupon wxCoupon = wxCouponMapper.selectById(wxOrderGroup.getCouponId());
            Integer status = wxCoupon.getStatus();
            if (status.equals(EnumCouponStatus.COUPON_STATUS_TAKE_OFFF.getCode())) {
                group.setStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING_CANCEL.getCode());
                returnMoney(group);
            }
            // 查看是否超时
            Date expiredDate = group.getExpiredDate();
            if (new Date().after(expiredDate)) {
                group.setStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING_OVERTIME.getCode());
                returnMoney(group);
            }
        }
    }

    @Override
    public List<WxOrderGroup> findList(WxOrderGroup group) {
        return wxOrderGroupMapper.selectList(new QueryWrapper(group));
    }

    @Override
    public PageInfo<WxOrderGroupMarketing> queryOrderGroupMarketingList(WxOrderGroupMarketing marketing, Integer pageIndex, Integer pageSize) {
        PageHelper.startPage(pageIndex, pageSize);
        List<WxOrderGroupMarketing> result = wxOrderGroupMapper.queryOrderGroupMarketingList(marketing);
        PageInfo<WxOrderGroupMarketing> pageInfo = new PageInfo<>(result);
        return pageInfo;
    }

    public void returnMoney(WxOrderGroup group) {
        //券失效或拼团超时 修改 拼团的状态
        wxOrderGroupMapper.updateById(group);
        WxOrder order = new WxOrder();
        order.setTenantId(group.getTenantId());
        order.setOrderGroupId(group.getId());
        order.setOrderStatus(group.getStatus());
        wxOrderMapper.updateStatusByOrderGroupId(order);
        //获取APP信息
        WxAppinfo appinfo = new WxAppinfo();
        appinfo.setTenantId(order.getTenantId());
        appinfo.setType(EnumAppType.C.getCode());
        appinfo = wxAppinfoMapper.findList(appinfo).get(0);
        //退款流程
        WxOrder wxOrder = new WxOrder();
        wxOrder.setTenantId(group.getTenantId());
        wxOrder.setOrderGroupId(group.getId());
        List<WxOrder> list = wxOrderMapper.findList(wxOrder);
        for (WxOrder temp : list) {
            if (temp.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING_OVERTIME.getCode())
                    || temp.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING_CANCEL.getCode())) {
                boolean has = wxRefundOrderService.hasRefundOrder(order.getId(), EnumRefundStatus.REFUND_SUCCESS.getCode());
                if (!has) {
                    //去库存
                    wxOrderService.stockBack(temp);
                    wxRefundOrderService.returnMoney(appinfo, temp.getId());
                }
            }
        }
    }
}
