package io.github.mightguy.symspell.solr.eventlistner;

import io.github.mightguy.spellcheck.symspell.api.SpellChecker;
import io.github.mightguy.spellcheck.symspell.common.DictionaryItem;
import io.github.mightguy.spellcheck.symspell.exception.SpellCheckException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.Fields;
import org.apache.lucene.index.MultiFields;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.CharsRefBuilder;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrEventListener;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.search.SolrIndexSearcher;

@Slf4j
public class CustomSpellCheckListner implements SolrEventListener {

  private final SolrCore core;
  private final SpellChecker checker;
  private final List<String> fieldArr;

  /**
   * Constructor for listner
   * @param core
   * @param checker
   * @param fieldArr
   */
  public CustomSpellCheckListner(SolrCore core, SpellChecker checker, String[] fieldArr) {
    this.core = core;
    this.checker = checker;
    this.fieldArr = Arrays.asList(fieldArr);
  }

  @Override
  public void postCommit() {
    // Nothing to do at post commit
  }

  @Override
  public void postSoftCommit() {
    // Nothing to do at pre commit
  }

  @Override
  public void newSearcher(SolrIndexSearcher newSearcher, SolrIndexSearcher currentSearcher) {
    // firstSearcher event Or New Searcher Event
    try {
      log.info("Loading spell index for spellchecker: "
          + checker);
      reload(newSearcher, checker);
    } catch (IOException | SpellCheckException e) {
      log.error("Exception in reloading spell check index for spellchecker: ", e);
    }
  }

  /**
   * Init method
   * @param args
   */
  @Override
  public void init(NamedList args) {
    // Nothing to do at init
  }

  /**
   * Relod method of spellcheck listner
   * @param newSearcher
   * @param checker
   * @throws IOException
   * @throws SpellCheckException
   */
  public void reload(SolrIndexSearcher newSearcher, SpellChecker checker)
      throws IOException, SpellCheckException {

    DirectoryReader productsIndexReader = newSearcher.getIndexReader();
    Fields fields = MultiFields.getFields(productsIndexReader);
    IndexSchema schema = newSearcher.getCore().getLatestSchema();
    long time = System.currentTimeMillis();
    for (String field : fields) {
      if (!fieldArr.contains(field)) {
        continue;
      }
      FieldType type = schema.getField(field).getType();
      int insertionsCount = 0;
      for (TermsEnum iterator = fields.terms(field).iterator(); iterator.next() != null; ) {
        BytesRef term = iterator.term();
        CharsRefBuilder charsRefBuilder = new CharsRefBuilder();
        type.indexedToReadable(term, charsRefBuilder);
        insertionsCount++;
        checker.getDataHolder().addItem(
            new DictionaryItem(charsRefBuilder.toString().trim(), (double) iterator.totalTermFreq(),
                0.0));
      }
      log.info("Spellcheck Dictionary populated for Field Name {}, Count {}", field,
          insertionsCount);
    }
    log.info("Data for SpellChecker  was populated. Time={} ms",
        (System.currentTimeMillis() - time));
  }

}