package org.nl.config.lucene;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.BytesRef;

import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * lucene查询器
 */
@Slf4j
public class Searcher {

    public static Map<String, Object> search(String indexDir, String ext,Map whereJson) throws Exception {
        //获取要查询的路径，也就是索引所在的位置
        Directory dir = FSDirectory.open(Paths.get(indexDir));
        IndexReader reader = DirectoryReader.open(dir);
        IndexSearcher searcher = new IndexSearcher(reader);
        // 实际上Lucene本身不支持分页。因此我们需要自己进行逻辑分页。我们要准备分页参数：
        int pageSize = Integer.parseInt(whereJson.get("size").toString());// 每页条数
        int pageNum = Integer.parseInt(whereJson.get("page").toString());// 当前页码

        BooleanQuery.Builder booleanQueryBuilder = new BooleanQuery.Builder();
        //时间范围查询
        String startDate = (String) whereJson.get("begin_time");
        String endDate = (String) whereJson.get("end_time");

        if (startDate == null){
            Calendar calendar=Calendar.getInstance();
            calendar.set(1970, 0, 1);
            startDate = DateUtil.format(calendar.getTime(),"yyyy-MM-dd HH:mm:ss.SSS");
        }else{
            startDate = getDate(startDate);
        }
        if (endDate == null){
            endDate = DateUtil.format(new DateTime(),"yyyy-MM-dd HH:mm:ss.SSS");
        } else {
            endDate = getDate(endDate);
        }
        TermRangeQuery termRangeQuery = new TermRangeQuery("logTime", new BytesRef(startDate), new BytesRef(endDate), true, true);
        booleanQueryBuilder.add(termRangeQuery,BooleanClause.Occur.MUST);
        if (whereJson.get("device_code") != null){
            Query termQuery = new TermQuery(new Term("device_code", (String) whereJson.get("device_code")));
            booleanQueryBuilder.add(termQuery,BooleanClause.Occur.MUST);
        }
        if (whereJson.get("method") != null){
            Query termQuery = new TermQuery(new Term("method", (String) whereJson.get("method")));
            booleanQueryBuilder.add(termQuery,BooleanClause.Occur.MUST);
        }
        if (whereJson.get("status_code") != null){
            Query termQuery = new TermQuery(new Term("status_code", (String) whereJson.get("status_code")));
            booleanQueryBuilder.add(termQuery,BooleanClause.Occur.MUST);
        }
        if (whereJson.get("requestparam") != null){
            WildcardQuery query = new  WildcardQuery(new Term("requestparam", "*"+(String) whereJson.get("requestparam")+"*"));
            booleanQueryBuilder.add(query,BooleanClause.Occur.MUST);
        }
        if (whereJson.get("responseparam") != null){
            WildcardQuery query = new  WildcardQuery(new Term("responseparam", "*"+(String) whereJson.get("responseparam")+"*"));
            booleanQueryBuilder.add(query,BooleanClause.Occur.MUST);
        }
        if (whereJson.get("blurry") != null) {
            WildcardQuery query = new  WildcardQuery(new Term("fieldContent", "*"+(String) whereJson.get("blurry")+"*"));
            booleanQueryBuilder.add(query, BooleanClause.Occur.MUST);
        }

        TopFieldCollector collector = TopFieldCollector.create(new Sort(new SortField("time", SortField.Type.LONG,true)), 20000, 0);
        searcher.search(booleanQueryBuilder.build(), collector);
        TopDocs topDocs = collector.topDocs(pageNum*pageSize, pageSize);
        int totalSize = collector.getTotalHits();
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;

        List<JSONObject> list = new ArrayList<>();
        for (ScoreDoc scoreDoc : scoreDocs) {
            Document doc = reader.document(scoreDoc.doc);
            JSONObject object = new JSONObject();
            object.put("content",doc.get("fieldContent"));
//            object.put("trace_id",doc.get("trace_id"));
            object.put("device_code",doc.get("device_code"));
            object.put("logTime",doc.get("logTime"));
            object.put("method",doc.get("method"));
            object.put("status_code",doc.get("status_code"));
            object.put("requestparam",doc.get("requestparam"));
            object.put("responseparam",doc.get("responseparam"));
            if(doc.get("fieldContent") != null) {
                list.add(object);
            }
        }
        reader.close();
        dir.close();
        JSONObject jo = new JSONObject();
        jo.put("content", list);
        jo.put("totalElements", totalSize);
        return jo;
    }

    public static String getDate(String timeString) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");//时间格式
        Date date = sdf.parse(timeString);
        timeString = DateUtil.format(date, "yyyy-MM-dd HH:mm:ss.SSS");//格式化后的时间
        return timeString;
    }
}
