package cn.reghao.tnb.search.esapp.log.db;

import cn.reghao.jutil.jdk.web.db.BaseCrud;
import cn.reghao.jutil.jdk.web.db.BaseQuery;
import cn.reghao.tnb.search.esapp.log.model.po.AccessLog;
import com.mongodb.MongoBulkWriteException;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.model.InsertManyOptions;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.InsertManyResult;
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.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author reghao
 * @date 2025-08-14 14:35:00
 */
@Repository
public class AccessLogMongo implements BaseCrud<AccessLog>, BaseQuery<AccessLog> {
    private final String colName = "AccessLog";
    private final MongoTemplate mongoTemplate;
    private final MongoConverter mongoConverter;
    private final int pageSize = 100;

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

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

    @Override
    public void saveAll(List<AccessLog> 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(AccessLog accessLog) {
    }

    @Override
    public void delete(AccessLog accessLog) {
        Query query = new Query();
        query.addCriteria(Criteria.where("requestId").is(accessLog.getRequestId()));
        DeleteResult deleteResult = mongoTemplate.remove(query, colName);
    }

    public void deleteByBefore(long before) {
        Query query = new Query();
        query.addCriteria(Criteria.where("requestTime").lt(before));
        DeleteResult deleteResult = mongoTemplate.remove(query, colName);
    }

    public MongoCursor<Document> getCursor(Map<String, Object> map) {
        Document filter = new Document();
        filter.putAll(map);
        return mongoTemplate.getCollection(colName).find(filter, Document.class).noCursorTimeout(true).cursor();
    }

    public List<AccessLog> findAll(long page) {
        Query query = new Query();
        query.skip((page - 1) * pageSize).limit(pageSize);
        query.with(Sort.by(new Sort.Order(Sort.Direction.DESC, "requestTime")));
        return mongoTemplate.find(query, AccessLog.class, colName);
    }

    public List<AccessLog> findAll() {
        Query query = new Query();
        query.limit(pageSize);
        query.with(Sort.by(new Sort.Order(Sort.Direction.DESC, "requestTime")));
        return mongoTemplate.find(query, AccessLog.class, colName);
    }

    public List<AccessLog> findByTargetServer(String targetServer) {
        Query query = new Query();
        query.addCriteria(Criteria.where("targetServer").is(targetServer));
        query.with(Sort.by(new Sort.Order(Sort.Direction.DESC, "requestTime")));
        return mongoTemplate.find(query, AccessLog.class, colName);
    }
}
