package com.sv.service.oms;

import com.enums.VenueTypeEnum;
import com.github.pagehelper.PageHelper;
import com.sv.dto.oms.VenueLessonOmsDTO;
import com.sv.entity.Platform;
import com.sv.entity.VenueLesson;
import com.sv.entity.VenueLessonTicket;
import com.sv.exception.oms.OmsException;
import com.sv.mapper.VenueLessonMapper;
import com.sv.mapper.VenueLessonTagMapper;
import com.sv.mapper.VenueLessonTicketMapper;
import com.sv.service.common.OSSClientUtil;
import com.sv.service.common.PlatformService;
import com.sv.service.common.RedisLock;
import com.ydd.framework.core.common.Pagination;
import com.ydd.framework.core.service.CacheService;
import com.ydd.framework.core.service.impl.BaseServiceImpl;
import com.ydd.framework.core.service.impl.WxXCXService;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;

import javax.annotation.Resource;
import java.io.InputStream;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static com.sv.entity.Constants.LESSON_TICKET_LOCK_KEY;

/**
 * Service - 场馆课程
 *
 * @author zhaoziyu
 * @since 2018-08-06
 */
@Service("VenueLessonServiceOms")
@Transactional(readOnly = true)
public class VenueLessonService extends BaseServiceImpl {

    private final Logger logger = LoggerFactory.getLogger(VenueLessonService.class);

    @Resource
    private VenueLessonMapper venueLessonMapper;

    @Resource
    private VenueLessonTicketMapper venueLessonTicketMapper;

    @Resource
    private VenueLessonTagMapper venueLessonTagMapper;

    @Resource
    private CacheService cacheService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private PlatformService platformService;

    @Resource
    private OSSClientUtil ossClientUtil;

    /**
     * 创建场馆课程
     *
     * @param venueLesson 场馆课程
     */
    @Transactional(rollbackFor = Exception.class)
    public void save(VenueLessonOmsDTO venueLesson) {
        venueLesson.setVeneuType(VenueTypeEnum.FITNESS.value);
        validateLessonDate(venueLesson);
        RedisLock redisLock = new RedisLock(redisTemplate,LESSON_TICKET_LOCK_KEY+venueLesson.getId());
        if (venueLesson.getId() != null && venueLesson.getId() > 0) {
            synchronized ("lesson" + venueLesson.getId().toString().intern()) {
                venueLessonMapper.deleteImagesById(venueLesson.getId());
                venueLessonTagMapper.deleteByLessonId(venueLesson.getId());
                VenueLesson dbVenueLesson = venueLessonMapper.findById(venueLesson.getId());
                if (venueLesson.getNum() > dbVenueLesson.getNum()) {
                    //新增票
                    dbVenueLesson.setNum(venueLesson.getNum() - dbVenueLesson.getNum());
                    insertLessonTicket(dbVenueLesson);
                } else if (venueLesson.getNum() < dbVenueLesson.getNum()) {
                    //减少票
                    deleteLessonTicket(venueLesson, dbVenueLesson.getNum(), dbVenueLesson.getNum() - venueLesson.getNum(),redisLock);
                }
                // 更新
                venueLessonMapper.update(venueLesson);
            }
        } else {
            venueLesson.setPlatformId(1);
            venueLesson.setSaleNum(0);
            // 新建
            Platform platform = platformService.findById(1);
            venueLessonMapper.insert(venueLesson);
            InputStream inputStream = WxXCXService.getNewInstance(platform.getAppId(), platform.getSecret(),"wx_xcx_token",cacheService).getXCXQrCode("pages/myBookings/index",venueLesson.getId().toString(),"190");
            String url = ossClientUtil.uploadImg(inputStream,"qrcode.png");
            venueLesson.setQrCode(url);
            venueLessonMapper.update(venueLesson);

            insertLessonTicket(venueLesson);
        }
        venueLessonMapper.insertImages(venueLesson.getLessonImage(), venueLesson.getId());
        if (venueLesson.getTags() != null && venueLesson.getTags().size() > 0){
            venueLessonTagMapper.insertTags(venueLesson.getId(), venueLesson.getTags());
        }

        /**
         * 解除课程库存锁
         */
        redisLock.unlock();
    }

    /**
     * 检查课程时间是否有冲突
     *
     * @param venueLesson
     */
    private void validateLessonDate(VenueLessonOmsDTO venueLesson) {

        DateTimeFormatter df = DateTimeFormatter.ofPattern("HH:mm");
        Integer count = venueLessonMapper.countByTime(df.format(venueLesson.getStartTime()), df.format(venueLesson.getEndTime()), venueLesson.getVenueId(), venueLesson.getVeneuType(), venueLesson.getId(), DateFormatUtils.format(venueLesson.getDate(), "yyyy-MM-dd"));
        if (count > 0) {
            throw new OmsException("该时间段与其他课程有冲突！请检查后再试");
        }
        //检查该教练在某个时间段是否有课程冲突
        count = venueLessonMapper.countByTimeAndCoach(df.format(venueLesson.getStartTime()), df.format(venueLesson.getEndTime()), venueLesson.getId(), DateFormatUtils.format(venueLesson.getDate(), "yyyy-MM-dd"), venueLesson.getCoachId());
        if (count > 0){
            throw new OmsException("该教练在这个时间段有其他课程!请检查后再试");
        }
    }

    /**
     * 减少课程出售数量
     *  @param venueLesson
     * @param oldNum      原始数量
     * @param count       减去数量
     * @param redisLock
     */
    private void deleteLessonTicket(VenueLesson venueLesson, Integer oldNum, Integer count, RedisLock redisLock) {
        try {
            //给当前课程的库存加锁 保证库存数据一致性
            boolean flag = redisLock.lock();
            if(!flag){
                throw new OmsException("减少课程库存超时，可能当前有用户正在购买，请稍后再试!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if ((oldNum - venueLesson.getSaleNum()) >= count) {
            //减去还没有售卖的票
            List<VenueLessonTicket> tickets = venueLessonTicketMapper.findNoUsedTicket(venueLesson.getId());
            if (tickets == null || tickets.size() <= 0) {
                redisLock.unlock();
                throw new OmsException("当前课程已售完，修改售卖数量失败");
            }
            if (tickets.size() < count) {
                redisLock.unlock();
                throw new OmsException("当前课程已经售卖" + (venueLesson.getNum() - tickets.size()) + "张，修改数量失败");
            }
            for (int i = 1; i <= (oldNum-count); i++) {
                tickets.remove(0);
            }
            venueLessonTicketMapper.deletedTickets(tickets, venueLesson.getId());
        } else {
            redisLock.unlock();
            throw new OmsException("当前课程已经售卖" + venueLesson.getSaleNum() + "张，修改数量失败");
        }
    }

    /**
     * 添加课程票据
     *
     * @param venueLesson
     */
    private void insertLessonTicket(VenueLesson venueLesson) {
        Set<String> tickets = new HashSet<>();
        int i = 0;
        do {
            String ticket = generateTicket();
            //判断ticket不重复
            if (tickets.add(ticket))
                i++;
        } while (i < venueLesson.getNum());
        List<String> t = Arrays.asList(tickets.toArray(new String[tickets.size()]));
        if (tickets.size() >= 2000) {
            int count = tickets.size() / 1000;
            count += tickets.size() % 1000 > 0 ? 1 : 0;
            for (int j = 0; j < count; j++) {
                int toIndex = 1000 * (j + 1);
                if (j == count - 1) {
                    toIndex = tickets.size();
                }
                insertTicket(t.subList(1000 * j, toIndex),venueLesson);
            }
        } else
            insertTicket(t,venueLesson);

    }

    private void insertTicket(List<String> t,VenueLesson venueLesson) {
        try {
            venueLessonTicketMapper.insertTickets(t, venueLesson.getVenueId(), venueLesson.getVeneuType(), venueLesson.getId());
        } catch (DuplicateKeyException exception) {
            throw new OmsException("增加销售数量失败！请再试一次！");
        }
    }

    private String generateTicket() {
        String ticket = RandomUtils.nextInt(100, 10000000) + "";
        return StringUtils.leftPad(ticket, 7, "0");
    }

    /**
     * 更新场馆课程
     *
     * @param venueLesson 场馆课程
     */

    @Transactional
    public void update(VenueLesson venueLesson) {
        venueLessonMapper.update(venueLesson);
    }

    /**
     * 删除场馆课程
     *
     * @param id 编号
     * @return 删除数量
     */

    @Transactional
    public Integer delete(Integer id) {
        if (id == null || id <= 0) {
            return 0;
        }
        return venueLessonMapper.delete(id);
    }

    /**
     * 删除场馆课程
     *
     * @param ids 编号数组
     * @return 删除数量
     */

    @Transactional
    public Integer deleteByIds(Integer[] ids) {
        if (ids == null || ids.length == 0) {
            return 0;
        }
        for(Integer id : ids){
            VenueLesson venueLesson = venueLessonMapper.findById(id);
            if(venueLesson.getSaleNum() > 0){
                throw new OmsException("该课程已经被购买，不允许删除！");
            }
        }
        return venueLessonMapper.deleteByIds(ids);
    }

    /**
     * 查询场馆课程
     *
     * @param id 编号
     * @return 场馆课程
     */
    public VenueLesson findByIdForOms(Integer id) {
        return venueLessonMapper.findByIdForOms(id);
    }

    /**
     * 查询场馆课程
     *
     * @param pagination 分页信息
     * @return 分页结果
     */

    public Pagination findPage(Pagination pagination, String leftTime, String rightTime) {
        PageHelper.startPage(pagination.getPage(), pagination.getPageSize());
        pagination.setQueryResult(venueLessonMapper.findAllForOms(leftTime, rightTime));
        return pagination;
    }

    /**
     * 查看教练有多少课程
     * @param id
     * @return
     */
    public Integer countByCoachId(Integer id){
        return venueLessonMapper.countByCoachId(id);
    }

}

