package cn.reghao.tnb.search.app.lucene;

import cn.reghao.tnb.search.app.model.po.VideoText;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.*;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.springframework.stereotype.Service;
import org.wltea.analyzer.lucene.IKAnalyzer;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;

/**
 * @author reghao
 * @date 2023-03-02 09:28:58
 */
@Service
public class LuceneIndex {
    private final LuceneDocument luceneDocument;
    private final String indexDirPath;
    private final Analyzer luceneAnalyzer = new IKAnalyzer();
    private final Directory directory;
    private final IndexWriter indexWriter;

    public LuceneIndex(LuceneDocument luceneDocument) throws IOException {
        this.luceneDocument = luceneDocument;
        this.indexDirPath = "/opt/data/bntdata/jsearch";
        this.directory = FSDirectory.open(Paths.get(indexDirPath));
        this.indexWriter = getIndexWriter();
    }

    public IndexWriter getIndexWriter() throws IOException {
        File indexDir = new File(indexDirPath);
        Directory indexDirectory = FSDirectory.open(indexDir.toPath());

        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(luceneAnalyzer);
        return new IndexWriter(indexDirectory, indexWriterConfig);
    }

    private IndexReader getIndexReader() throws IOException {
        Directory directory = FSDirectory.open(Paths.get(indexDirPath));
        IndexReader indexReader = DirectoryReader.open(directory);
        return indexReader;
    }

    public void createVideoTextIndex(VideoText videoText) throws IOException {
        Document document = luceneDocument.getVideoTextDoc(videoText);
        indexWriter.addDocument(document);
        indexWriter.commit();
    }

    public void updateIndex(String videoId, Document document) throws IOException {
        if (document != null) {
            // Lucene 没有提供更新接口, 更新操作实际是先删除后再添加
            indexWriter.updateDocument(new Term("videoId", videoId), document);
            indexWriter.commit();
        }
    }

    public Document getDocument(String videoId) throws IOException {
        IndexReader indexReader = DirectoryReader.open(directory);
        Query query = new TermQuery(new Term("videoId", videoId));
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);
        TopDocs topDocs = indexSearcher.search(query, 1);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        if (scoreDocs.length == 1) {
            Document document = indexReader.document(scoreDocs[0].doc);
            return document;
        }

        return null;
    }

    public void deleteIndex(String videoId) throws IOException {
        indexWriter.deleteDocuments(new Term("videoId", videoId));
        indexWriter.commit();
    }

    public void createIndex(Document document) throws IOException {
        IndexWriter indexWriter = getIndexWriter();
        indexWriter.addDocument(document);
        indexWriter.commit();
        indexWriter.close();
    }

    public void createIndex(List<Document> list) throws IOException {
        IndexWriter indexWriter = getIndexWriter();
        list.forEach(doc -> {
            try {
                indexWriter.addDocument(doc);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

        indexWriter.commit();
        indexWriter.close();
    }

    public void updateIndex(Document document) throws IOException {
        Directory directory = FSDirectory.open(Paths.get(indexDirPath));
        IndexWriterConfig config = new IndexWriterConfig(luceneAnalyzer);
        IndexWriter indexWriter = new IndexWriter(directory, config);

        indexWriter.updateDocument(new Term("name", "李白"), document);
        indexWriter.commit();
        indexWriter.close();
    }

    public void deleteIndex() throws IOException {
        Directory directory = FSDirectory.open(Paths.get(indexDirPath));
        Analyzer analyzer = new IKAnalyzer();
        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        IndexWriter indexWriter = new IndexWriter(directory, config);

        indexWriter.deleteDocuments(new Term("name", "李白"));
        indexWriter.commit();
        indexWriter.close();
    }

    public void deleteAllIndex() throws IOException {
        Directory directory = FSDirectory.open(Paths.get(indexDirPath));
        Analyzer analyzer = new IKAnalyzer();
        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        IndexWriter indexWriter = new IndexWriter(directory, config);

        indexWriter.deleteAll();
        indexWriter.commit();
        indexWriter.close();
    }

    public void check() throws IOException {
        IndexReader indexReader = DirectoryReader.open(directory);
        // 总共的索引文档
        int maxDocs = indexReader.maxDoc();
        // 有效的索引文档
        int numDocs = indexReader.numDocs();
        // 被标记删除的索引文档
        int numDeletedDocs = indexReader.numDeletedDocs();
    }

    public void restore() {
    }

    /**
     * 彻底删除文档
     *
     * @param
     * @return
     * @date 2025-04-02 11:31:44
     */
    public void forceDelete() throws IOException {
        indexWriter.forceMergeDeletes();
    }
}
