package com.search.lucene.indexers;

import com.opencsv.CSVReader;
import com.search.lucene.indexers.abstractions.IFileIndexer;
import com.search.lucene.settings.LuceneConstants;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;

public class CSVFileIndexer implements IFileIndexer {
    private final IndexWriter writer;

    public CSVFileIndexer(String indexDirectoryPath) throws IOException {
        //this directory will contain the indexes
        Directory indexDirectory =
                FSDirectory.open(Paths.get(indexDirectoryPath));

        //create the indexer
        writer = new IndexWriter(indexDirectory, new IndexWriterConfig(new StandardAnalyzer()));
    }

    public void close() throws CorruptIndexException, IOException {
        writer.close();
    }

    private ArrayList<Document> getDocument(File file) throws IOException {
        ArrayList<Document> documents = new ArrayList<>();

        FileReader filereader = new FileReader(file);

        CSVReader csvReader = new CSVReader(filereader);

        String[] nextRecord;
        String[] columns;
        columns = csvReader.readNext();
        int line = 1;
        while ((nextRecord = csvReader.readNext()) != null) {
            line++;
            for (int i = 0; i < nextRecord.length; i++) {
                Document document = new Document();

                document.add(new TextField(LuceneConstants.COLUMN, columns[i], Field.Store.YES));
                document.add(new TextField(LuceneConstants.VALUE, nextRecord[i], Field.Store.YES));
                document.add(new TextField(LuceneConstants.LINE, Integer.toString(line), Field.Store.YES));
                document.add(new StringField(LuceneConstants.FILE_PATH, file.getCanonicalPath(), Field.Store.YES));
                document.add(new StringField(LuceneConstants.FILE_NAME, file.getName(), Field.Store.YES));
                documents.add(document);
                System.out.print(nextRecord[i] + "\t");
            }
            System.out.println();
        }

        return documents;
    }

    private void indexFile(File file) throws IOException {
        System.out.println("Indexing " + file.getCanonicalPath());
        ArrayList<Document> documents = getDocument(file);
        for (var document : documents) {
            writer.addDocument(document);
        }
    }

    @Override
    public int createIndex(String dataDirectoryPath, FileFilter filter)
            throws IOException {
        File[] files = new File(dataDirectoryPath).listFiles();

        assert files != null;

        for (File file : files) {
            if (!file.isDirectory()
                    && !file.isHidden()
                    && file.exists()
                    && file.canRead()
                    && filter.accept(file)
            ) {
                indexFile(file);
            }
        }
        return writer.numRamDocs();
    }
}