package com.apobates.forum.core.impl;

import com.apobates.forum.core.dao.BoardDao;
import com.apobates.forum.core.dao.PostsDao;
import com.apobates.forum.core.dao.TopicDao;
import com.apobates.forum.core.entity.ActionEventDescriptor;
import com.apobates.forum.core.entity.Board;
import com.apobates.forum.core.entity.BoardActionCollection;
import com.apobates.forum.core.entity.Posts;
import com.apobates.forum.core.entity.Topic;
import com.apobates.forum.core.entity.TopicActionCollection;
import com.apobates.forum.event.elderly.ActionEventCulpritor;
import com.apobates.forum.event.elderly.ForumActionEnum;
import com.apobates.forum.utils.cache.AbstractCubbyHole;
import java.util.Optional;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.CodeSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Core模块中关于ActionDescriptor注解拦截器
 * @author xiaofanku
 * @since 20200529
 */
@Aspect
public class CoreModuleActionEventAspect {
    @Autowired
    private BoardDao boardDao;
    @Autowired
    private TopicDao topicDao;
    @Autowired
    private PostsDao postsDao;
    @Autowired
    private AbstractCubbyHole<ActionEventDescriptor> cubbyHole;
    //@Autowired
    //private BoardActionCollectionDao boardActionCollectionDao;
    //@Autowired
    //private TopicActionCollectionDao topicActionCollectionDao;
    private final static Logger logger = LoggerFactory.getLogger(CoreModuleActionEventAspect.class);
    
    @Before("execution(* com.apobates.forum.core.impl.service.*.*(..)) && @annotation(actionDescriptor)")
    public void enjoy(JoinPoint joinPoint, ActionDescriptor actionDescriptor){
        logger.info("[CAT]12>1 method start");
    }
    
    @AfterReturning(
            pointcut="@annotation(actionDescriptor) && args(.., culpritor)",
            returning="retVal")
    public void check(
            JoinPoint joinPoint, 
            ActionEventCulpritor culpritor, 
            ActionDescriptor actionDescriptor, 
            Object retVal) throws Throwable{
        //方法名
        String methodName = joinPoint.getSignature().toShortString(); //TopicServiceImpl.browse(..)
        logger.info("[CAT]12>3 methodName: "+methodName);
        String[] classNameMethodName = methodName.replace("(..)", "").split("\\.");
        if(classNameMethodName == null || classNameMethodName.length != 2) {
            return;
        }
        //主键
        long primaryKey;
        if(!actionDescriptor.isBool()) {
            primaryKey = (Long)retVal;
        }else {
            //
            CodeSignature signature=(CodeSignature)joinPoint.getStaticPart().getSignature();
            primaryKey = getPrimaryKey(joinPoint.getArgs(), signature.getParameterNames(), actionDescriptor.keyName());
        }
        logger.info("[CAT]12>4 entity primary key value: "+primaryKey);
        if(classNameMethodName[0].startsWith("TopicService") || classNameMethodName[0].startsWith("PostsService")) {
            topicAndPostsAction(classNameMethodName[0], primaryKey, culpritor, actionDescriptor);
        }
        if(classNameMethodName[0].startsWith("BoardService")) {
            boardAction(primaryKey, culpritor, actionDescriptor);
        }
    }
    
    private void topicAndPostsAction(String className, long id, ActionEventCulpritor culpritor, ActionDescriptor actionDescriptor) {
        if(id <= 0 || culpritor.getMemberId() <= 0) { 
            logger.info("[CAT]12>5 primary key args is Illegal");
            return;
        }
        TopicActionCollection entity;
        if(className.contains("PostsService")) {
            entity = buildPostsAction(id, culpritor, actionDescriptor);
        }else {
            entity = buildTopicAction(id, culpritor, actionDescriptor);
        }
        //topicActionCollectionDao.save(entity);
        cubbyHole.put(entity);
    }
    
    private TopicActionCollection buildTopicAction(long topicId, ActionEventCulpritor culpritor, ActionDescriptor actionDescriptor){
        Topic topic = topicDao.findOne(topicId).orElseGet(Topic::new);
        //积分计算时的受益会员ID,一般均为操作者
        long rodeMember = culpritor.getMemberId();
        if(ForumActionEnum.getReverseActions().contains(actionDescriptor.action())){ // 当前操作要反转受益会员
            rodeMember = topic.getMemberId();
        }
        TopicActionCollection entity = new TopicActionCollection(actionDescriptor.action(), topic.getTitle(), topicId, 0L, culpritor, rodeMember);
        return entity;
    }
    
    private TopicActionCollection buildPostsAction(long postsId, ActionEventCulpritor culpritor, ActionDescriptor actionDescriptor){
        Posts posts = postsDao.findOne(postsId).orElseGet(Posts::new);
        long topicId = posts.getTopicId();
        //积分计算时的受益会员ID,一般均为操作者
        long rodeMember = culpritor.getMemberId();
        if(ForumActionEnum.getReverseActions().contains(actionDescriptor.action())){ // 当前操作要反转受益会员
            rodeMember = posts.getMemberId();
        }
        TopicActionCollection entity = new TopicActionCollection(actionDescriptor.action(), String.format("%s在%d楼的回复", posts.getMemberNickname(), posts.getFloorNumber()), topicId, postsId, culpritor, rodeMember);
        return entity;
    }
    
    private void boardAction(Long primaryKey, ActionEventCulpritor culpritor, ActionDescriptor actionDescriptor) {
        if(culpritor.getMemberId() <= 0){
            logger.info("[CAT]12>6.9 member is guest");
            return ;
        }
        Optional<Board> obj = boardDao.findOne(primaryKey);
        if(!obj.isPresent()) {
            logger.info("[CAT]12>7 board primary key args is Illegal");
            return ;
        }
        Board board = obj.get();
        //积分计算时的受益会员ID,一般均为操作者
        long rodeMember = culpritor.getMemberId();
        logger.info("[CAT]12>7.1 board id: "+board.getId()+", title: "+board.getTitle());
        BoardActionCollection entity = new BoardActionCollection(actionDescriptor.action(), board.getTitle(), primaryKey, culpritor, rodeMember);
        //boardActionCollectionDao.save(entity);
        cubbyHole.put(entity);
    }
    
    private Long getPrimaryKey(Object[] paramValues, String[] paramNames, String keyName) {
        Long key = -1L;
        for(int i=0;i<paramValues.length;i++){
            if(!"null".equalsIgnoreCase(keyName) && keyName.equals(paramNames[i])){
                try {
                    key = (Long)paramValues[i];
                }catch(ClassCastException e) {
                    logger.info("[CAT]12>3.1 loop primary key fail, err: "+e.getMessage());
                    key = 0L;
                }
            }
        }
        return key;
    }
}