package com.search.lucene.indexers.implementations;

import com.opencsv.CSVReader;
import com.search.lucene.file.filters.abstractions.IFileFilter;
import com.search.lucene.file.filters.implementations.CSVFileFilter;
import com.search.lucene.indexers.abstractions.IFileIndexer;
import com.search.lucene.settings.Constants;
import com.search.lucene.settings.RepresentationSchema;
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.FileReader;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;

public class CSVFileIndexer implements IFileIndexer {
    private final IndexWriter writer;
    private final IFileFilter filter;

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

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

    @Override
    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++;
            StringBuilder csvRowStringBuilder = new StringBuilder();
            for (String s : nextRecord) {
                csvRowStringBuilder.append(s);
            }
            String csvRow = csvRowStringBuilder.toString();
            for (int i = 0; i < nextRecord.length; i++) {

                Document document = new Document();

                document.add(new TextField(Constants.COLUMN, columns[i], Field.Store.YES));
                document.add(new TextField(RepresentationSchema.TYPE, RepresentationSchema.CSV, Field.Store.YES));
                document.add(new TextField(Constants.CSV_ROW, csvRow, Field.Store.YES));
                document.add(new TextField(Constants.VALUE, nextRecord[i], Field.Store.YES));
                document.add(new TextField(Constants.ROW, Integer.toString(line), Field.Store.YES));
                document.add(new StringField(Constants.FILE_PATH, file.getCanonicalPath(), Field.Store.YES));
                document.add(new StringField(Constants.FILE_NAME, file.getName(), Field.Store.YES));
                documents.add(document);

            }

        }

        return documents;
    }

    private void indexFile(File file) throws IOException {
        ArrayList<Document> documents = getDocument(file);
        for (var document : documents) {
            writer.addDocument(document);
        }
    }

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

        if (files == null){
            return -1000;
        }

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