package com.duiba.tuia.youtui.web.service.impl;

import cn.com.duiba.tuia.activity.center.api.constant.LayerSkinType;
import cn.com.duiba.tuia.activity.center.api.dto.ButtonDto;
import cn.com.duiba.tuia.activity.center.api.dto.LayerSkinDto;
import cn.com.duiba.tuia.activity.center.api.remoteservice.RemoteSkinService;
import cn.com.duiba.tuia.activity.center.api.remoteservice.RemoteSystemConfigService;
import com.duiba.tuia.youtui.web.model.req.SkinReq;
import com.duiba.tuia.youtui.web.service.BaseService;
import com.duiba.tuia.youtui.web.service.SkinService;
import com.duiba.tuia.youtui.web.service.SystemConfigService;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * Created by wubo on 2017/8/22.
 */
@Service
public class SkinServiceImpl extends BaseService implements SkinService, InitializingBean {

    /**
     * 弹层缓存key
     */
    private static final String                      CONSTANT_CACHE           = "constant";

    /**
     * 默认弹层id配置key
     */
    private static final String                      DEFAULT_LAYER_CONFIG_KEY = "default_layer_id";
    private static volatile Long                     alipayRandomLayerId      = null;
    private static volatile Long                     alipayQuotaLayerId       = null;
    private static volatile Long                     thanksLayerId       = null;
    private static volatile Long                     qbRandomLayerId      = null;
    private static volatile Long                     qbQuotaLayerId       = null;
    private static volatile Long                     billRandomLayerId = null;
    private static volatile Long                     billQuotaLayerId = null;

    @Autowired
    private RemoteSkinService                        remoteSkinService;
    @Autowired
    private SystemConfigService                      systemConfigService;
    /**
     * 非广告弹层缓存 支付宝定额，支付宝随机，谢谢参与
     */
    private LoadingCache<String, List<LayerSkinDto>> constantLayerCache;

    /**
     * 广告弹层缓存
     */
    private LoadingCache<Long, LayerSkinDto>         couponLayerCache;

    /**
     * 客服按钮样式缓存
     */
    private LoadingCache<Long, ButtonDto> buttonCache;

    /**
     * 根据类型查询的弹层缓存
     */
    private LoadingCache<Integer,List<LayerSkinDto>> layerTypeCache;

    @Override
    public void afterPropertiesSet() throws Exception {
        constantLayerCache = CacheBuilder.newBuilder().maximumSize(5)// 最多存5个
                                         .refreshAfterWrite(1, TimeUnit.MINUTES)// 缓存1分钟刷新一次(load不到新数据时仍返回就数据)
                                         .expireAfterWrite(5, TimeUnit.MINUTES)// 缓存5分钟强制刷新一次
                                         .build(new CacheLoader<String, List<LayerSkinDto>>() {

                                             @Override
                                             public List<LayerSkinDto> load(String key) throws Exception {
                                                 return remoteSkinService.selectConstantLayerSkin().getResult();
                                             }
                                         });

        couponLayerCache = CacheBuilder.newBuilder().maximumSize(500)// 最多存500个
                                       .refreshAfterWrite(1, TimeUnit.MINUTES)// 缓存1分钟刷新一次(load不到新数据时仍返回就数据)
                                       .expireAfterWrite(5, TimeUnit.MINUTES)// 缓存5分钟强制刷新一次
                                       .build(new CacheLoader<Long, LayerSkinDto>() {

                                           @Override
                                           public LayerSkinDto load(Long key) throws Exception {
                                               if (key == null) {
                                                   return null;
                                               }
                                               return remoteSkinService.selectLayerSkin(key).getResult();
                                           }
                                       });

        buttonCache = CacheBuilder.newBuilder().maximumSize(500)// 最多存500个
                .refreshAfterWrite(1, TimeUnit.MINUTES)// 缓存1分钟刷新一次(load不到新数据时仍返回就数据)
                .expireAfterWrite(5, TimeUnit.MINUTES)// 缓存5分钟强制刷新一次
                .build(new CacheLoader<Long, ButtonDto>() {

                    @Override
                    public ButtonDto load(Long key) throws Exception {
                        return remoteSkinService.getButtonById(key).getResult();
                    }
                });

        layerTypeCache =  CacheBuilder.newBuilder().maximumSize(50)
                .refreshAfterWrite(1, TimeUnit.MINUTES)// 缓存1分钟刷新一次(load不到新数据时仍返回就数据)
                .expireAfterWrite(5, TimeUnit.MINUTES)// 缓存5分钟强制刷新一次
                .build(new CacheLoader<Integer, List<LayerSkinDto>>() {
                    @Override
                    public List<LayerSkinDto> load(Integer type) throws Exception {
                        return selectLayerByType(type);
                    }
                });
    }

    @Override
    public List<LayerSkinDto> selectAllLayerSkin(SkinReq req) throws ExecutionException {
        List<LayerSkinDto> rs = Lists.newArrayList();
        // 查询固定弹层(支付宝，qb，虚拟奖品，话费等)
        List<LayerSkinDto> layers = constantLayerCache.get(CONSTANT_CACHE);
        rs.addAll(layers);

        // 查询广告弹层(abTest配置，每次概率出)
        if (req.getCouponSkinId() != null) {
            LayerSkinDto couponLayer = couponLayerCache.get(req.getCouponSkinId());
            if (couponLayer != null) {
                rs.add(couponLayer);
            }
            // 行业广告弹层
            addLayerByType(rs, LayerSkinType.COUPON_EDUCATION.getType());
            addLayerByType(rs, LayerSkinType.COUPON_INSURANCE.getType());
            addLayerByType(rs, LayerSkinType.COUPON_LOAN.getType());

        }
        // 查询特殊弹层
        addLayerByType(rs, LayerSkinType.getCustomSkinType(req.getActivityId()));

        // 查询谢谢参与弹层
        if (!LayerSkinType.THANKS.getType().equals(req.getThankLayerType())) {
            addLayerByType(rs, req.getThankLayerType());
        }

        return rs;

    }

    private void addLayerByType(List<LayerSkinDto> layers, Integer skinType) {
        if (skinType != null) {
            LayerSkinDto layer = this.selectSpecialLayer(skinType);
            if (layer != null) {
                layers.add(layer);
            }
        }
    }

    @Override
    public Long selectDefaultLayerId() {

        String defaultLayerId = this.systemConfigService.getSystemConfig(DEFAULT_LAYER_CONFIG_KEY);
        if (StringUtils.isNotBlank(defaultLayerId)) {
            return Long.parseLong(defaultLayerId);
        }
        return null;
    }

    @Override
    public Long selectAlipayRandomLayerId() {
        try {
            if (alipayRandomLayerId == null) {
                synchronized (this) {
                    if (alipayRandomLayerId == null) {
                        alipayRandomLayerId = getAlipaySkinId(LayerSkinType.ALIPAY_RANDOM);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("查询随机支付宝弹层id异常", e);
        }
        return alipayRandomLayerId;
    }

    @Override
    public Long selectAlipayQuotaLayerId() {
        try {
            if (alipayQuotaLayerId == null) {
                synchronized (this) {
                    if (alipayQuotaLayerId == null) {
                        alipayQuotaLayerId = getAlipaySkinId(LayerSkinType.ALIPAY_QUOTA);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("查询定额支付宝弹层id异常", e);
        }
        return alipayQuotaLayerId;
    }

    @Override
    public Long selectThanksLayerId() {
        try {
            if (thanksLayerId == null) {
                synchronized (this) {
                    if (thanksLayerId == null) {
                        thanksLayerId = getAlipaySkinId(LayerSkinType.THANKS);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("查询谢谢参与弹层id异常", e);
        }
        return thanksLayerId ==  null ? 0L : thanksLayerId;
    }

    @Override
    public Long selectQbQuotaLayerId() {
        try {
            if (qbQuotaLayerId == null) {
                synchronized (this) {
                    if (qbQuotaLayerId == null) {
                        qbQuotaLayerId = getAlipaySkinId(LayerSkinType.QB_QUOTA);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("查询定额支付宝弹层id异常", e);
        }
        return qbQuotaLayerId;
    }

    @Override
    public Long selectQbRandomLayerId() {
        try {
            if (qbRandomLayerId == null) {
                synchronized (this) {
                    if (qbRandomLayerId == null) {
                        qbRandomLayerId = getAlipaySkinId(LayerSkinType.QB_RANDOM);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("查询定额支付宝弹层id异常", e);
        }
        return qbRandomLayerId;
    }

    @Override
    public Long selectBillQuotaLayerId() {
        try {
            if (billQuotaLayerId == null) {
                synchronized (this) {
                    if (billQuotaLayerId == null) {
                        billQuotaLayerId = getAlipaySkinId(LayerSkinType.BILL_QUOTA);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("查询定额话费弹层id异常", e);
        }
        return billQuotaLayerId;
    }

    @Override
    public Long selectBillRandomLayerId() {
        try {
            if (billRandomLayerId == null) {
                synchronized (this) {
                    if (billRandomLayerId == null) {
                        billRandomLayerId = getAlipaySkinId(LayerSkinType.BILL_RANDOM);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("查询随机话费弹层id异常", e);
        }
        return billRandomLayerId;
    }


    private Long getAlipaySkinId(LayerSkinType alipayType) throws ExecutionException {
        List<LayerSkinDto> layers = this.constantLayerCache.get(CONSTANT_CACHE);
        if (CollectionUtils.isNotEmpty(layers)) {
            for (LayerSkinDto dto : layers) {
                if (alipayType.getType().equals(dto.getSkinType())) {
                    return dto.getId();
                }
            }
        }
        return null;
    }

    @Override
    public ButtonDto getButtonById(Long id) throws ExecutionException {
        return buttonCache.get(id);
    }

    @Override
    public List<LayerSkinDto> selectLayerByTypeFromCache(Integer type) {
        try {
            return layerTypeCache.get(type);
        } catch (ExecutionException e) {
            logger.warn("selectLayerByTypeFromCache error", e);
            return Collections.emptyList();
        }
    }

    private List<LayerSkinDto> selectLayerByType(Integer type) {
        List<LayerSkinDto> rs = null;
        if (type != null) {
            rs = this.remoteSkinService.selectLayerSkinByType(type);
        }
        if (rs == null) {
            rs = Collections.emptyList();
        }
        return rs;
    }

    public LayerSkinDto selectSpecialLayer(Integer type) {
        LayerSkinDto rs = null;
        List<LayerSkinDto> layers = this.selectLayerByTypeFromCache(type);
        if (CollectionUtils.isNotEmpty(layers)) {
            LayerSkinDto layer = layers.get(0);
            if (StringUtils.isNotBlank(layer.getCode())) {//弹层样式代码非空时返回
                rs = layer;
            }
        }
        return rs;
    }

}
