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.ArticlePost;
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 ArticlePostMongo implements BaseCrud<ArticlePost>, BaseQuery<ArticlePost> {
    private final String colName = "ArticlePost";
    private final MongoTemplate mongoTemplate;
    private final MongoConverter mongoConverter;
    private final int pageSize = 20;

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

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

    @Override
    public void saveAll(List<ArticlePost> 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(ArticlePost articlePost) {
        articlePost.setUpdateTime(LocalDateTime.now());

        Document document = new Document();
        mongoConverter.write(articlePost, document);
        Document filter = new Document();
        filter.put("articleId", articlePost.getArticleId());
        mongoTemplate.getCollection(colName).replaceOne(filter, document);
    }

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

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

    public List<ArticlePost> findByUserId(long userId, long page) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.skip((page - 1) * pageSize).limit(pageSize);
        query.with(Sort.by(new Sort.Order(Sort.Direction.DESC, "updateTime")));
        return mongoTemplate.find(query, ArticlePost.class, colName);
    }

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