package com.yeqifu.bus.cache;

import com.yeqifu.bus.entity.Customer;
import com.yeqifu.bus.entity.Goods;
import com.yeqifu.sys.cache.CachePool;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;

/**
 * @Author: 落亦-
 * @Date: 2019/12/5 16:39
 * 该类是一个切面类，用于实现业务缓存的相关切面逻辑
 */
@Aspect
@Component
@EnableAspectJAutoProxy
public class BusinessCacheAspect {
    /**
     * 日志出处
     */
    private Log log = LogFactory.getLog(BusinessCacheAspect.class);

    /**
     * 声明一个缓存容器，从 CachePool 中获取 CACHE_CONTAINER
     */
    private Map<String,Object> CACHE_CONTAINER = CachePool.CACHE_CONTAINER;


    /**
     * 声明客户的切面表达式，用于匹配 CustomerServiceImpl 中的不同方法
     */
    private static final String POINTCUT_CUSTOMER_ADD="execution(* com.yeqifu.bus.service.impl.CustomerServiceImpl.save(..))";
    private static final String POINTCUT_CUSTOMER_UPDATE="execution(* com.yeqifu.bus.service.impl.CustomerServiceImpl.updateById(..))";
    private static final String POINTCUT_CUSTOMER_GET="execution(* com.yeqifu.bus.service.impl.CustomerServiceImpl.getById(..))";
    private static final String POINTCUT_CUSTOMER_DELETE="execution(* com.yeqifu.bus.service.impl.CustomerServiceImpl.removeById(..))";
    private static final String POINTCUT_CUSTOMER_BATCHDELETE="execution(* com.yeqifu.bus.service.impl.CustomerServiceImpl.removeByIds(..))";

    private static final String CACHE_CUSTOMER_PROFIX="customer:";

    /**
     * 添加客户切入
     * @param joinPoint 连接点，代表被拦截的方法
     * @return 方法的执行结果
     * @throws Throwable 可能抛出的异常
     */
    @Around(value = POINTCUT_CUSTOMER_ADD)
    public Object cacheCustomerAdd(ProceedingJoinPoint joinPoint) throws Throwable {
        //取出第一个参数，这里假设第一个参数是 Customer 类型
        Customer object = (Customer) joinPoint.getArgs()[0];
        // 执行被拦截的方法
        Boolean res = (Boolean) joinPoint.proceed();
        if (res){
            // 如果执行成功，将客户对象添加到缓存容器中，以 customer:id 为键存储
            CACHE_CONTAINER.put(CACHE_CUSTOMER_PROFIX + object.getId(),object);
        }
        return res;
    }

    /**
     * 查询客户切入
     * @param joinPoint 连接点，代表被拦截的方法
     * @return 方法的执行结果
     * @throws Throwable 可能抛出的异常
     */
    @Around(value = POINTCUT_CUSTOMER_GET)
    public Object cacheCustomerGet(ProceedingJoinPoint joinPoint) throws Throwable {
        //取出第一个参数，这里假设第一个参数是 Integer 类型的客户 id
        Integer object = (Integer) joinPoint.getArgs()[0];
        //从缓存里面取客户对象
        Object res1 = CACHE_CONTAINER.get(CACHE_CUSTOMER_PROFIX + object);
        if (res1!=null){
            log.info("已从缓存里面找到客户对象"+CACHE_CUSTOMER_PROFIX + object);
            return res1;
        }else {
            // 若缓存中不存在，则从数据库中查询，将结果放入缓存，并打印日志信息
            log.info("未从缓存里面找到客户对象，从数据库中查询并放入缓存");
            Customer res2 =(Customer) joinPoint.proceed();
            CACHE_CONTAINER.put(CACHE_CUSTOMER_PROFIX+res2.getId(),res2);
            return res2;
        }
    }

    /**
     * 更新客户切入方法
     * @param joinPoint 连接点，代表被拦截的方法
     * @return 方法的执行结果
     * @throws Throwable 可能抛出的异常
     */
    @Around(value = POINTCUT_CUSTOMER_UPDATE)
    public Object cacheCustomerUpdate(ProceedingJoinPoint joinPoint) throws Throwable {
        //取出第一个参数，这里假设第一个参数是 Customer 类型
        Customer customerVo = (Customer) joinPoint.getArgs()[0];
        // 执行被拦截的方法
        Boolean isSuccess = (Boolean) joinPoint.proceed();
        if (isSuccess){
            // 从缓存中获取客户对象
            Customer customer =(Customer) CACHE_CONTAINER.get(CACHE_CUSTOMER_PROFIX + customerVo.getId());
            if (null==customer){
                customer=new Customer();
            }
            // 将更新后的客户信息复制到缓存对象中
            BeanUtils.copyProperties(customerVo,customer);
            log.info("客户对象缓存已更新"+CACHE_CUSTOMER_PROFIX + customerVo.getId());
            CACHE_CONTAINER.put(CACHE_CUSTOMER_PROFIX+customer.getId(),customer);
        }
        return isSuccess;
    }

    /**
     * 删除客户切入方法
     * @param joinPoint 连接点，代表被拦截的方法
     * @return 方法的执行结果
     * @throws Throwable 可能抛出的异常
     */
    @Around(value = POINTCUT_CUSTOMER_DELETE)
    public Object cacheCustomerDelete(ProceedingJoinPoint joinPoint) throws Throwable {
        //取出第一个参数，这里假设第一个参数是 Integer 类型的客户 id
        Integer id = (Integer) joinPoint.getArgs()[0];
        // 执行被拦截的方法
        Boolean isSuccess = (Boolean) joinPoint.proceed();
        if (isSuccess){
            // 删除缓存中的客户对象
            CACHE_CONTAINER.remove(CACHE_CUSTOMER_PROFIX+id);
        }
        return isSuccess;
    }

    /**
     * 批量删除客户切入方法
     * @param joinPoint 连接点，代表被拦截的方法
     * @return 方法的执行结果
     * @throws Throwable 可能抛出的异常
     */
    @Around(value = POINTCUT_CUSTOMER_BATCHDELETE)
    public Object cacheCustomerBatchDelete(ProceedingJoinPoint joinPoint) throws Throwable {
        // 取出第一个参数，这里假设第一个参数是一个可序列化对象的集合
        @SuppressWarnings("unchecked")
        Collection<Serializable> idList = (Collection<Serializable>) joinPoint.getArgs()[0];
        // 执行被拦截的方法
        Boolean isSuccess = (Boolean) joinPoint.proceed();
        if (isSuccess) {
            for (Serializable id : idList) {
                // 遍历集合，删除每个客户的缓存
                CACHE_CONTAINER.remove(CACHE_CUSTOMER_PROFIX + id);
                log.info("客户对象缓存已删除" + CACHE_CUSTOMER_PROFIX + id);
            }
        }
        return isSuccess;
    }


    /**
     *  声明商品的切面表达式，用于匹配 GoodsServiceImpl 中的不同方法
     */
    private static final String POINTCUT_GOODS_ADD="execution(* com.yeqifu.bus.service.impl.GoodsServiceImpl.save(..))";
    private static final String POINTCUT_GOODS_UPDATE="execution(* com.yeqifu.bus.service.impl.GoodsServiceImpl.updateById(..))";
    private static final String POINTCUT_GOODS_GET="execution(* com.yeqifu.bus.service.impl.GoodsServiceImpl.getById(..))";
    private static final String POINTCUT_GOODS_DELETE="execution(* com.yeqifu.bus.service.impl.GoodsServiceImpl.removeById(..))";

    private static final String CACHE_GOODS_PROFIX="goods:";

    /**
     * 添加商品切入
     * @param joinPoint 连接点，代表被拦截的方法
     * @return 方法的执行结果
     * @throws Throwable 可能抛出的异常
     */
    @Around(value = POINTCUT_GOODS_ADD)
    public Object cacheGoodsAdd(ProceedingJoinPoint joinPoint) throws Throwable {
        //取出第一个参数，这里假设第一个参数是 Goods 类型
        Goods object = (Goods) joinPoint.getArgs()[0];
        // 执行被拦截的方法
        Boolean res = (Boolean) joinPoint.proceed();
        if (res){
            // 如果执行成功，将商品对象添加到缓存容器中，以 goods:id 为键存储
            CACHE_CONTAINER.put(CACHE_GOODS_PROFIX + object.getId(),object);
        }
        return res;
    }

    /**
     * 添加商品切入方法
     * @param joinPoint 连接点，代表被拦截的方法
     * @return 方法的执行结果
     * @throws Throwable 可能抛出的异常
     */
    @Around(value = POINTCUT_GOODS_GET)
    public Object cacheGoodsGet(ProceedingJoinPoint joinPoint) throws Throwable {
        //取出第一个参数，这里假设第一个参数是 Integer 类型的商品 id
        Integer object = (Integer) joinPoint.getArgs()[0];
        //从缓存里面取商品对象
        Object res1 = CACHE_CONTAINER.get(CACHE_GOODS_PROFIX + object);
        if (res1!=null){
            // 若缓存中存在，则打印日志信息
            log.info("已从缓存里面找到商品对象"+CACHE_GOODS_PROFIX + object);
            return res1;
        }else {
            // 若缓存中不存在，则从数据库中查询，将结果放入缓存，并打印日志信息
            log.info("未从缓存里面找到商品对象，从数据库中查询并放入缓存");
            Goods res2 =(Goods) joinPoint.proceed();
            CACHE_CONTAINER.put(CACHE_GOODS_PROFIX+res2.getId(),res2);
            return res2;
        }
    }

    /**
     * 更新商品切入
     * @param joinPoint 连接点，代表被拦截的方法
     * @return 方法的执行结果
     * @throws Throwable 可能抛出的异常
     */
    @Around(value = POINTCUT_GOODS_UPDATE)
    public Object cacheGoodsUpdate(ProceedingJoinPoint joinPoint) throws Throwable {
        //取出第一个参数，这里假设第一个参数是 Goods 类型
        Goods goodsVo = (Goods) joinPoint.getArgs()[0];
        // 执行被拦截的方法
        Boolean isSuccess = (Boolean) joinPoint.proceed();
        if (isSuccess){
            // 从缓存中获取商品对象
            Goods goods =(Goods) CACHE_CONTAINER.get(CACHE_GOODS_PROFIX + goodsVo.getId());
            if (null==goods){
                goods=new Goods();
            }
            // 将更新后的商品信息复制到缓存对象中
            BeanUtils.copyProperties(goodsVo,goods);
            log.info("商品对象缓存已更新"+CACHE_GOODS_PROFIX + goodsVo.getId());
            // 将更新后的商品对象重新放入缓存
            CACHE_CONTAINER.put(CACHE_GOODS_PROFIX+goods.getId(),goods);
        }
        return isSuccess;
    }

    /**
     * 删除商品切入
     * @param joinPoint 连接点，代表被拦截的方法
     * @return 方法的执行结果
     * @throws Throwable 可能抛出的异常
     */
    @Around(value = POINTCUT_GOODS_DELETE)
    public Object cacheGoodsDelete(ProceedingJoinPoint joinPoint) throws Throwable {
        //取出第一个参数，这里假设第一个参数是 Integer 类型的商品 id
        Integer id = (Integer) joinPoint.getArgs()[0];
        // 执行被拦截的方法
        Boolean isSuccess = (Boolean) joinPoint.proceed();
        if (isSuccess){
            //删除缓存中的商品对象
            CACHE_CONTAINER.remove(CACHE_GOODS_PROFIX+id);
        }
        return isSuccess;
    }

    
}
