package cn.reghao.tnb.search.app.comment.db.mongo;

import cn.reghao.jutil.jdk.web.db.BaseCrud;
import cn.reghao.jutil.jdk.web.db.BaseQuery;
import cn.reghao.tnb.search.app.comment.model.po.UserComment;
import com.mongodb.MongoBulkWriteException;
import com.mongodb.client.model.InsertManyOptions;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.InsertManyResult;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author reghao
 * @date 2023-02-01 14:19:02
 */
@Slf4j
@Repository
public class UserCommentMongo implements BaseCrud<UserComment>, BaseQuery<UserComment> {
    private final String colName = "UserComment";
    private final MongoTemplate mongoTemplate;
    private final MongoConverter mongoConverter;
    private final int pageSize = 20;

    public UserCommentMongo(MongoTemplate mongoTemplate, MongoConverter mongoConverter) {
        this.mongoTemplate = mongoTemplate;
        this.mongoConverter = mongoConverter;
    }

    @Override
    public UserComment save(UserComment userComment) {
        Document doc = new Document();
        mongoConverter.write(userComment, doc);
        mongoTemplate.getCollection(colName).insertOne(doc);
        return null;
    }

    @Override
    public void saveAll(List<UserComment> list) {
        List<Document> documents = list.stream()
                .map(t -> {
                    Document doc = new Document();
                    mongoConverter.write(t, doc);
                    return doc;
                })
                .collect(Collectors.toList());

        InsertManyOptions options = new InsertManyOptions();
        // 忽略 insert 失败的文档
        options.ordered(false);
        try {
            InsertManyResult result = mongoTemplate.getCollection(colName).insertMany(documents, options);
        }  catch (MongoBulkWriteException ignore) {
        }
    }

    @Override
    public void update(UserComment userComment) {
        userComment.setUpdateTime(LocalDateTime.now());

        Document document = new Document();
        mongoConverter.write(userComment, document);
        Document filter = new Document();
        mongoTemplate.getCollection(colName).replaceOne(filter, document);
    }

    @Override
    public void delete(UserComment userComment) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(userComment.getId()));
        DeleteResult deleteResult = mongoTemplate.remove(query, UserComment.class);
    }

    public long countByPostId(String postId) {
        Document filter = new Document();
        filter.put("postId", postId);
        filter.put("pCommentId", 0);
        return mongoTemplate.getCollection(colName).countDocuments(filter);
    }

    public List<UserComment> findByPostId(String postId, long pageNumber) {
        Query query = new Query();
        query.addCriteria(Criteria.where("postId").is(postId));
        query.addCriteria(Criteria.where("pCommentId").is(0));
        query.with(Sort.by(new Sort.Order(Sort.Direction.DESC, "publishAt")));
        query.skip((pageNumber - 1) * pageSize).limit(pageSize);
        return mongoTemplate.find(query, UserComment.class, colName);
    }

    public long countChildComment(long commentId) {
        Document filter = new Document();
        filter.put("pCommentId", commentId);
        return mongoTemplate.getCollection(colName).countDocuments(filter);
    }

    public List<UserComment> findByParentId(long commentId, long pageNumber, int pageSize) {
        Query query = new Query();
        query.addCriteria(Criteria.where("pCommentId").is(commentId));
        query.with(Sort.by(new Sort.Order(Sort.Direction.ASC, "publishAt")));
        query.skip((pageNumber - 1) * pageSize).limit(pageSize);
        return mongoTemplate.find(query, UserComment.class, colName);
    }

    public UserComment findByCommentId(long commentId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("commentId").is(commentId));
        List<UserComment> list = mongoTemplate.find(query, UserComment.class, colName);
        return list.isEmpty() ? null : list.get(0);
    }
}
