package com.iformall.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
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.ResultData;
import com.iformall.domain.po.*;
import com.iformall.domain.vo.WxCouponChannelVo;
import com.iformall.enums.EnumCouponChannelStatus;
import com.iformall.enums.EnumCouponChannelType;
import com.iformall.enums.EnumCouponStatus;
import com.iformall.enums.EnumGameStatus;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.WxCouponChannelMapper;
import com.iformall.mapper.WxCouponOrderMapper;
import com.iformall.mapper.WxGameActionLogMapper;
import com.iformall.mapper.WxGameMapper;
import com.iformall.service.*;
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.*;

@Service
public class WxGameServiceImpl implements WxGameService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
    WxGameMapper wxGameMapper;

	@Autowired
    WxCouponChannelMapper wxCouponChannelMapper;

    @Autowired
    WxCouponService wxCouponService;

    @Autowired
    WxCouponOrderMapper wxCouponOrderMapper;

	@Autowired
    WxCouponChannelService wxCouponChannelService;

    @Autowired
    WxGameTemplateService wxGameTemplateService;

    @Autowired
    WxGameActionLogMapper wxGameActionLogMapper;

    @Autowired
    private QrCodeService qrCodeService;

    @Override
    public PageInfo<WxGame> listAsPage(WxGame record, Integer pageIndex, Integer pageSize) {
        PageInfo<WxGame> page = PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxGameMapper.findList(record));
        if (page.getSize() > 0) {
            for (WxGame game : page.getList()) {
                game.setGameTemplate(wxGameTemplateService.getById(game.getGameId()));
            }
        }
        return page;
    }

    @Override
    public WxGame getOne(WxGame wxGame) {
        List<WxGame> list = wxGameMapper.findList(wxGame);
        WxGame record = null;
        if (list.size() >0) {
            record = list.get(new Random().nextInt(list.size()));
        }

        if (record != null) {
            record.setGameTemplate(wxGameTemplateService.getById(record.getGameId()));
            record.setCouponIdsList(getParams(record));
        }

        return record;
    }

    @Override
    public WxGame getOneGame(WxGame wxGame) {
        try {
            WxGame record = wxGameMapper.selectOne(new QueryWrapper(wxGame));
            if (record != null) {
                record.setGameTemplate(wxGameTemplateService.getById(record.getGameId()));
                record.setCouponIdsList(getParams(record));
            }
            return record;
        } catch (Exception e) {
            logger.error("find game error: " + e.getMessage());
        }
        return null;
    }


    @Override
    public ResultData addActionLog(Long userId, Long gameId, Long orderId) {

        WxCouponOrder wxCouponOrder = new WxCouponOrder();
        wxCouponOrder.setCUserId(userId);
        wxCouponOrder.setOrderId(orderId);

        if (orderId != 0) {
            try {
                wxCouponOrder = wxCouponOrderMapper.selectOne(new QueryWrapper(wxCouponOrder));
            } catch (Exception e) {
                return new ResultData(ErrorCode.COUPON_ORDER_IS_NULL);
            }

            if (wxCouponOrder == null)
                return new ResultData(ErrorCode.COUPON_ORDER_IS_NULL);
        }
        final IdWorker idWorker = IdWorker.get();
        WxGameActionLog wxGameActionLog = new WxGameActionLog();
        wxGameActionLog.setUserId(userId);
        wxGameActionLog.setTenantId(wxCouponOrder.getTenantId());
        wxGameActionLog.setGameId(gameId);
        wxGameActionLog.setCouponOrderId(wxCouponOrder.getOrderId());
        wxGameActionLog.setId(idWorker.nextId());
        wxGameActionLog.setCreateTime(new Date());
        wxGameActionLogMapper.insert(wxGameActionLog);
        return new ResultData();
    }

    @Override
    public ResultData getCount(Long gameId, Long userId) {

        WxGame wxGame = wxGameMapper.selectById(gameId);
        if (wxGame == null)
            return new ResultData(ErrorCode.GAME_NOT_FOUND);

        WxGameActionLog wxGameActionLog = new WxGameActionLog();
        wxGameActionLog.setTenantId(wxGame.getTenantId());
        wxGameActionLog.setUserId(userId);
        wxGameActionLog.setGameId(gameId);

        int playLimit = wxGame.getPlayLimit();
        int AwardLimit = wxGame.getAwardLimit();
        int playCount = wxGameActionLogMapper.getPlayCount(wxGameActionLog);
        int AwardCount = wxGameActionLogMapper.getAwardCount(wxGameActionLog);

        boolean playAble  = !(( playLimit != 0 &&  playCount >= playLimit)
                        || (AwardLimit != 0 &&  AwardCount >= AwardLimit));

        Map<String,Object> map = new HashMap();
        map.put("playLimit",playLimit);
        map.put("AwardLimit",AwardLimit);
        map.put("playCount",playCount);
        map.put("AwardCount",AwardCount);
        map.put("playAble",playAble);
        return new ResultData(map);
    }


    private List<Object> getParams(WxGame record) {
        // 获取已上架的CouponChannel
        WxCouponChannel couponChannelQ = new WxCouponChannel();
        couponChannelQ.setTenantId(record.getTenantId());
        couponChannelQ.setTargetAd(EnumCouponChannelType.COUPON_CHANNEL_ID_GAME.getCode());
        couponChannelQ.setSubTargetId(record.getId());
        couponChannelQ.setStatus(EnumCouponChannelStatus.STATUS_THROW_IN.getCode());
        List<WxCouponChannelVo> wxCouponChannelVos = wxCouponChannelService.listVo(couponChannelQ);
        Map<Long, WxCouponChannelVo> wxCouponChannelsMap = new HashMap<Long, WxCouponChannelVo>();
        for(WxCouponChannelVo wxCouponChannelVo: wxCouponChannelVos) {
            wxCouponChannelsMap.put(wxCouponChannelVo.getCouponId(), wxCouponChannelVo);
        }

        // get game's coupon
        List couponIdsList = new ArrayList();
        JSONArray couponChannelIds = JSON.parseArray(record.getCouponIds());
        for(int i=0; i<couponChannelIds.size();i++) {
            JSONObject couponChanObj = (JSONObject) couponChannelIds.get(i);
            Long couponId = couponChanObj.getLong("couponId");

            WxCouponChannelVo couponChannelVo = wxCouponChannelsMap.get(couponId);
            if (couponChannelVo != null) {
                couponChannelVo.setGameWeight(couponChanObj.getInteger("weight"));
                couponIdsList.add(couponChannelVo);
            }
        }

        return couponIdsList;
    }

    @Override
    public WxGame getById(Long id) {
        WxGame game = wxGameMapper.selectById(id);
        if (game != null) {
            game.setGameTemplate(wxGameTemplateService.getById(game.getGameId()));
            game.setCouponIdsList(getParams(game));
        }
        return game;
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    @Override
    public void saveOrUpdate(WxGame record) {
        if (record.getId() == null) {
            //record.setId(UUID.randomUUID().toString().replaceAll("-", ""));
            final IdWorker idWorker = IdWorker.get();
        	record.setId(idWorker.nextId());
            wxGameMapper.insert(record);
        } else {
            wxGameMapper.updateById(record);
        }

        record = wxGameMapper.selectById(record);
        if (record.getStatus().equals(EnumGameStatus.STATUS_THROW_IN.getCode())) {
            addOrUpdateCouponChannelBatch(JSONArray.parseArray(record.getCouponIds()), record);
        } else {
            delCouponChannelBatch(record);
        }
    }

    private void delCouponChannelBatch(WxGame record) {
        // couponChannel 下架
        WxCouponChannel wxCouponChannelQ = new WxCouponChannel();
        wxCouponChannelQ.setTenantId(record.getTenantId());
        wxCouponChannelQ.setTargetAd(EnumCouponChannelType.COUPON_CHANNEL_ID_GAME.getCode());
        wxCouponChannelQ.setSubTargetId(record.getId());
        wxCouponChannelQ.setStatus(EnumCouponChannelStatus.STATUS_THROW_IN.getCode());
        List<WxCouponChannel> wxCouponChannels = wxCouponChannelMapper.findList(wxCouponChannelQ);
        if (wxCouponChannels.size() > 0) {
            for (WxCouponChannel ch : wxCouponChannels) {
                ch.setStatus(EnumCouponChannelStatus.STATUS_TAKE_OFFF.getCode());
                ch.setUpdateDate(new Date());
                wxCouponChannelMapper.updateById(ch);
            }
        }
    }

    private void addOrUpdateCouponChannelBatch(List couponIds, WxGame record) {
        // 获取已上架的CouponChannel
        WxCouponChannel wxCouponChannelQ = new WxCouponChannel();
        wxCouponChannelQ.setTenantId(record.getTenantId());
        wxCouponChannelQ.setTargetAd(EnumCouponChannelType.COUPON_CHANNEL_ID_GAME.getCode());
        wxCouponChannelQ.setSubTargetId(record.getId());
        wxCouponChannelQ.setStatus(EnumCouponChannelStatus.STATUS_THROW_IN.getCode());
        List<WxCouponChannel> wxCouponChannels = wxCouponChannelMapper.findList(wxCouponChannelQ);
        Map<Long, WxCouponChannel> wxCouponChannelsMap = new HashMap<Long, WxCouponChannel>();
        for(WxCouponChannel wxCouponChannel: wxCouponChannels) {
            wxCouponChannelsMap.put(wxCouponChannel.getCouponId(), wxCouponChannel);
        }

        // 上架 couponChannel 更新
        for(int i=0; i<couponIds.size();i++) {
            JSONObject obj = (JSONObject)couponIds.get(i);
            Long couponId = obj.getLong("couponId");
            int weight = obj.getIntValue("weight");
            try {
                saveOrUpdateCouponChannel(couponId, wxCouponChannelsMap, record);
            } catch (MallinkException e) {
                logger.error(e.getMessage());
            }
        }

        // 下架更新
        if (!wxCouponChannelsMap.isEmpty()) {
            for (WxCouponChannel wxCouponChannel : wxCouponChannelsMap.values()) {
                wxCouponChannel.setStatus(EnumCouponChannelStatus.STATUS_TAKE_OFFF.getCode());
                wxCouponChannel.setUpdateDate(new Date());
                wxCouponChannelMapper.updateById(wxCouponChannel);
            }
        }
    }

    public void saveOrUpdateCouponChannel(Long couponId, Map<Long, WxCouponChannel> wxCouponChannelsMap, WxGame record){

        WxCoupon wxCoupon = wxCouponService.getById(couponId);
        if (wxCoupon == null) {
            throw new MallinkException(ErrorCode.COUPON_IS_EMPTY);
        }
        if (wxCoupon.getStatus() != EnumCouponStatus.COUPON_STATUS_THROW_IN.getCode()) {
            throw new MallinkException(ErrorCode.COUPON_IS_TAKE_OFF);
        }
        if (wxCoupon.getValidEndDate() != null && wxCoupon.getValidEndDate().before(new Date())) {
            throw new MallinkException(ErrorCode.COUPON_IS_EXPIRED);
        }

        // 更新已有的couponChannel
        WxCouponChannel wxCouponChannel = wxCouponChannelsMap.get(couponId);
        if (wxCouponChannel != null) {
            wxCouponChannel.setStatus(EnumCouponChannelStatus.STATUS_THROW_IN.getCode());
            wxCouponChannel.setBeginTime(record.getValidStartDate());
            wxCouponChannel.setEndTime(record.getValidEndDate());
            wxCouponChannel.setUpdateDate(new Date());
            wxCouponChannelMapper.updateById(wxCouponChannel);
            wxCouponChannelsMap.remove(couponId);
        } else {
            // 不存在的新增
            wxCouponChannel = new WxCouponChannel();
            wxCouponChannel.setBeginTime(record.getValidStartDate());
            wxCouponChannel.setEndTime(record.getValidEndDate());
            wxCouponChannel.setStatus(EnumCouponChannelStatus.STATUS_THROW_IN.getCode());
            wxCouponChannel.setCouponId(couponId);
            wxCouponChannel.setType(wxCoupon.getType());
            wxCouponChannel.setTargetAd(EnumCouponChannelType.COUPON_CHANNEL_ID_GAME.getCode());
            wxCouponChannel.setTenantId(wxCoupon.getTenantId());
            wxCouponChannel.setBusiness(wxCoupon.getBusiness());
            wxCouponChannel.setSubBusiness(wxCoupon.getSubBusiness());
            wxCouponChannel.setTitle(wxCoupon.getTitle());
            wxCouponChannel.setSubTargetId(record.getId());
            final IdWorker idWorker = IdWorker.get();
            wxCouponChannel.setId(idWorker.nextId());
            wxCouponChannelMapper.insert(wxCouponChannel);

            String pageUrl = "pages/index/index";
            WxCouponChannel couponChannel = new WxCouponChannel();
            couponChannel.setId(wxCouponChannel.getId());
            couponChannel.setType(wxCouponChannel.getType());
            String param = couponChannel.getWeappScene();
            ResultData resultDataQ = qrCodeService.uploadQrcode(wxCoupon.getTenantId(),1,pageUrl,param,0,"","","卷");
            Map<String,String> map = (Map)resultDataQ.data;
            if(map!=null && map.get("url") !=null) {
                String url = map.get("url");
                couponChannel.setQrCode(url);
                wxCouponChannelMapper.updateById(couponChannel);
            }
        }
    }

    @Override
    public void deleteById(Long id) {
        wxGameMapper.deleteById(id);
    }
}
