package org.lym.pom.service.impl;

import com.mongodb.client.result.DeleteResult;
import org.lym.pom.notify.event.AttitudeAddEvent;
import org.lym.pom.notify.event.AttitudeRemoveEvent;
import org.lym.pom.notify.publisher.EventPublisher;
import org.lym.pom.repository.mongo.Attitude;
import org.lym.pom.repository.mongo.Attitude.RelatedType;
import org.lym.pom.service.AttitudeService;
import org.lym.pom.service.CommentService;
import org.lym.pom.service.PostService;
import org.shoulder.core.exception.CommonErrorCodeEnum;
import org.shoulder.core.util.AssertUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.stream.Collectors;

/**
 * 赞/踩 服务
 *
 * @author lym
 */
@Service
public class AttitudeServiceImpl implements AttitudeService {

    @Autowired
    private EventPublisher eventPublisher;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private CommentService commentService;

    @Autowired
    private PostService postService;

    @Override
    public boolean addAttitude(Attitude attitude) {
        AssertUtils.notNull(attitude.getRelatedId(), CommonErrorCodeEnum.ILLEGAL_PARAM);
        AssertUtils.notNull(attitude.getRelatedType(), CommonErrorCodeEnum.ILLEGAL_PARAM);
        AssertUtils.notNull(attitude.getRelatedUserId(), CommonErrorCodeEnum.ILLEGAL_PARAM);
        AssertUtils.notNull(attitude.getType(), CommonErrorCodeEnum.ILLEGAL_PARAM);

        // 查询目标对象存在
        Object target = null;
        if (attitude.getRelatedType().equals(Attitude.RelatedType.COMMENT.getStorageValue())) {
            target = commentService.queryCommentDetail(attitude.getRelatedId());
        } else if (attitude.getRelatedType().equals(RelatedType.MOMENT.getStorageValue())) {
            target = postService.queryPostDetail(attitude.getRelatedId());

        }
        // todo 其他的
        AssertUtils.notNull(target, CommonErrorCodeEnum.ILLEGAL_PARAM, "relatedObject not exists.");

        attitude.setCreateTime(System.currentTimeMillis());

        Attitude existedAttitude = mongoTemplate.findOne(Query.query(
                Criteria.where("relatedId").is(attitude.getRelatedId())
                        .and("relatedType").is(attitude.getRelatedType())
                        .and("relatedUserId").is(attitude.getRelatedUserId())
                        .and("type").is(attitude.getType())
        ), Attitude.class);
        if (existedAttitude != null) {
            return true;
        }
        Attitude savedAttitude = mongoTemplate.save(attitude);

        eventPublisher.publish(new AttitudeAddEvent(savedAttitude, target));
        return true;
    }

    /**
     * 移除赞，最多一个赞，根据挂载节点删，就算add时并发加多了，这里可以全删
     *
     * @param attitude 交互信息
     */
    @Override
    public void removeAttitude(Attitude attitude) {
        Query deleteQuery = Query.query(Criteria.where("relatedId").is(attitude.getRelatedId())
                .and("relatedType").is(attitude.getRelatedType())
                .and("creator").is(attitude.getCreator())
                .and("type").is(attitude.getType())
        );
        Attitude deletedAttitude = mongoTemplate.findOne(deleteQuery, Attitude.class);
        if(deletedAttitude == null) {
            // 不存在，返回
            return;
        }

        DeleteResult deleteResult = mongoTemplate.remove(deleteQuery, Attitude.class);
        if(deleteResult.wasAcknowledged()) {
            AssertUtils.isTrue(deleteResult.getDeletedCount() > 0, CommonErrorCodeEnum.DATA_STORAGE_FAIL);
        } else {
            deletedAttitude = mongoTemplate.findOne(deleteQuery, Attitude.class);
            AssertUtils.isNull(deletedAttitude, CommonErrorCodeEnum.DATA_STORAGE_FAIL);
        }

        eventPublisher.publish(new AttitudeRemoveEvent(attitude));
    }

    /**
     * 查询单条 Attitude
     *
     * @return 详情
     */
    @Override
    public Attitude queryAttitudeDetail(String relatedId, String relatedType, String userId) {
        AssertUtils.notBlank(relatedId, CommonErrorCodeEnum.ILLEGAL_PARAM);
        // todo 枚举校验
        AssertUtils.notBlank(relatedType, CommonErrorCodeEnum.ILLEGAL_PARAM);
        AssertUtils.notBlank(userId, CommonErrorCodeEnum.ILLEGAL_PARAM);
        Query query = Query.query(
                Criteria.where("relatedId").is(relatedId)
                        .and("relatedType").is(relatedType)
                        .and("userId").is(userId)
        );
        return mongoTemplate.findOne(query, Attitude.class);
    }

    @Override
    public Map<String, Integer> countAttitudeNumber(String relatedId, String relatedType) {
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(Criteria.where("relatedId").is(relatedId).and("relatedType").is(relatedType)),
                Aggregation.group("type").count().as("count")
        );
        AggregationResults<GroupCount> aggregationResult = mongoTemplate.aggregate(aggregation, "attitude", GroupCount.class);
        Map<String, Integer> result = aggregationResult.getMappedResults().stream()
                .collect(Collectors.toMap(g -> g._id, g -> g.count, (k1, k2) -> k2));

        return result;
    }

    public static class GroupCount {
        String _id;
        int count;
    }

}
