package de.duehl.vocabulary.japanese.logic.sort;

import java.util.List;

import de.duehl.basics.text.Text;
import de.duehl.vocabulary.japanese.data.symbol.Kanji;

/**
 * Diese Klasse berechnet zu einem Kanji aus einer Liste von nach bestimmten Suchkriterien
 * gefundenen Kanji anhand eines Suchbegriffs die Relevanz (je kleiner, desto besser).
 *
 * @version 1.01     2026-01-01
 * @author Christian Dühl
 */

public class KanjiRelevanceWeightingCalculator {

    private static final int WEIGHTENING_GERMAN_MEANING_PART_EQUALS_SEARCH = 1;
    private static final int WEIGHTENING_ON_LESUNG_MEANING_EQUALS_SEARCH = 2;
    private static final int WEIGHTENING_KUN_LESUNG_MEANING_EQUALS_SEARCH = 3;

    private static final int WEIGHTENING_LOWERED_GERMAN_MEANING_PART_EQUALS_LOWERED_SEARCH = 11;
    private static final int WEIGHTENING_LOWERED_ON_LESUNG_EQUALS_LOWERED_SEARCH = 12;
    private static final int WEIGHTENING_LOWERED_KUN_LESUNG_EQUALS_LOWERED_SEARCH = 13;

    private static final int WEIGHTENING_GERMAN_MEANING_PART_STARTS_WITH_SEARCH = 21;
    private static final int WEIGHTENING_ON_LESUNG_STARTS_WITH_SEARCH = 22;
    private static final int WEIGHTENING_KUN_LESUNG_STARTS_WITH_SEARCH = 23;

    private static final int WEIGHTENING_LOWERED_GERMAN_MEANING_PART_STARTS_WITH_LOWERED_SEARCH = 31;
    private static final int WEIGHTENING_LOWERED_ON_LESUNG_STARTS_WITH_LOWERED_SEARCH = 32;
    private static final int WEIGHTENING_LOWERED_KUN_LESUNG_STARTS_WITH_LOWERED_SEARCH = 33;

    private static final int WEIGHTENING_GERMAN_MEANING_PART_ENDS_WITH_SEARCH = 41;
    private static final int WEIGHTENING_ON_LESUNG_ENDS_WITH_SEARCH = 42;
    private static final int WEIGHTENING_KUN_LESUNG_ENDS_WITH_SEARCH = 43;

    private static final int WEIGHTENING_LOWERED_GERMAN_MEANING_PART_ENDS_WITH_LOWERED_SEARCH = 51;
    private static final int WEIGHTENING_LOWERED_ON_LESUNG_ENDS_WITH_LOWERED_SEARCH = 52;
    private static final int WEIGHTENING_LOWERED_KUN_LESUNG_ENDS_WITH_LOWERED_SEARCH = 53;

    private static final int WEIGHTENING_GERMAN_MEANING_PART_CONTAINS_SEARCH_AS_SINGLE_WORD = 61;
    private static final int WEIGHTENING_ON_LESUNG_CONTAINS_SEARCH_AS_SINGLE_WORD = 62;
    private static final int WEIGHTENING_KUN_LESUNG_CONTAINS_SEARCH_AS_SINGLE_WORD = 63;

    private static final int
            WEIGHTENING_LOWERED_GERMAN_MEANING_PART_CONTAINS_LOWERED_SEARCH_AS_SINGLE_WORD = 71;
    private static final int
            WEIGHTENING_LOWERED_ON_LESUNG_CONTAINS_LOWERED_SEARCH_AS_SINGLE_WORD = 72;
    private static final int
            WEIGHTENING_LOWERED_KUN_LESUNG_CONTAINS_LOWERED_SEARCH_AS_SINGLE_WORD = 73;

    private static final int NO_SPECIAL_WEIGHTENING = 999;


    private final List<String> germanMeaningParts;
    private final List<String> loweredGermanMeaningParts;
    private List<String> onLesungen;
    private List<String> loweredOnLesungen;
    private List<String> kunLesungen;
    private List<String> loweredKunLesungen;

    /** Der Suchbegriff, nach dem die Vokabel nach Relevanz bewertet werden soll. */
    private final String search;

    /**
     * Der Suchbegriff, nach dem die Kanji nach Relevanz bewertet werden soll in Kleinbuchstaben.
     */
    private String loweredCaseSearch;

    /**
     * Die Bewertung der Relevanz der Kanji.
     *
     * Eine höhere Relevanz drückt sich in einer kleineren Zahl aus.
     */
    private int weighting;

    /** Gibt an, ob die Gewichtung bereits gefunden wurde. */
    private boolean weighteningFound;

    /**
     * Konstruktor.
     *
     * @param kanji
     *            Die Kanji, deren Relevanz berechnet werden soll.
     * @param search
     *            Der Suchbegriff, nach dem die Kanji nach Relevanz bewertet werden soll.
     */
    public KanjiRelevanceWeightingCalculator(Kanji kanji, String search) {
        this.search = search;
        loweredCaseSearch = Text.toLowerCase(search);

        germanMeaningParts = kanji.getGermanMeanings();
        loweredGermanMeaningParts = Text.toLowerCase(germanMeaningParts);

        onLesungen = kanji.getOnLesungen();
        loweredOnLesungen = Text.toLowerCase(onLesungen);

        kunLesungen = kanji.getKunLesungen();
        loweredKunLesungen = Text.toLowerCase(kunLesungen);
    }

    /** Berechnet die Relevanz */
    public void calculate() {
        init();

        checkIfEqualsSearch();
        checkIfLoweredEqualsLoweredSearch();
        checkIfStartsWithSearch();
        checkIfLoweredStartsWithLoweredSearch();
        checkIfEndsWithSearch();
        checkIfLoweredEndsWithLoweredSearch();
        checkIfContainsSearchAsSingleWord();
        checkIfContainsLoweredSearchAsLoweredSingleWord();
    }

    private void init() {
        weighteningFound = false;
        weighting = NO_SPECIAL_WEIGHTENING;
    }

    private void checkIfEqualsSearch() {
        if (!weighteningFound) checkIfGermanMeaningEqualsSearch();
        if (!weighteningFound) checkIfOnLesungEqualsSearch();
        if (!weighteningFound) checkIfKunLesungEqualsSearch();
    }

    private void checkIfGermanMeaningEqualsSearch() {
        checkIfListElementEqualsSearch(germanMeaningParts,
                WEIGHTENING_GERMAN_MEANING_PART_EQUALS_SEARCH);
    }

    private void checkIfOnLesungEqualsSearch() {
        checkIfListElementEqualsSearch(onLesungen, WEIGHTENING_ON_LESUNG_MEANING_EQUALS_SEARCH);
    }

    private void checkIfKunLesungEqualsSearch() {
        checkIfListElementEqualsSearch(kunLesungen,
                WEIGHTENING_KUN_LESUNG_MEANING_EQUALS_SEARCH);
    }

    private void checkIfLoweredEqualsLoweredSearch() {
        if (!weighteningFound) checkIfLoweredGermanMeaningEqualsLoweredSearch();
        if (!weighteningFound) checkIfLoweredOnLesungEqualsLoweredSearch();
        if (!weighteningFound) checkIfLoweredKunLesungEqualsLoweredSearch();
    }

    private void checkIfLoweredGermanMeaningEqualsLoweredSearch() {
        checkIfListElementEqualsLoweredSearch(loweredGermanMeaningParts,
                WEIGHTENING_LOWERED_GERMAN_MEANING_PART_EQUALS_LOWERED_SEARCH);
    }

    private void checkIfLoweredOnLesungEqualsLoweredSearch() {
        checkIfListElementEqualsLoweredSearch(loweredOnLesungen,
                WEIGHTENING_LOWERED_ON_LESUNG_EQUALS_LOWERED_SEARCH);
    }

    private void checkIfLoweredKunLesungEqualsLoweredSearch() {
        checkIfListElementEqualsLoweredSearch(loweredKunLesungen,
                WEIGHTENING_LOWERED_KUN_LESUNG_EQUALS_LOWERED_SEARCH);
    }

    private void checkIfStartsWithSearch() {
        if (!weighteningFound) checkIfGermanMeaningStartsWithSearch();
        if (!weighteningFound) checkIfOnLesungStartsWithSearch();
        if (!weighteningFound) checkIfKunLesungStartsWithSearch();
    }

    private void checkIfGermanMeaningStartsWithSearch() {
        checkIfListElementStartsWithSearch(germanMeaningParts,
                WEIGHTENING_GERMAN_MEANING_PART_STARTS_WITH_SEARCH);
    }

    private void checkIfOnLesungStartsWithSearch() {
        checkIfListElementStartsWithSearch(onLesungen,
                WEIGHTENING_ON_LESUNG_STARTS_WITH_SEARCH);
    }

    private void checkIfKunLesungStartsWithSearch() {
        checkIfListElementStartsWithSearch(kunLesungen,
                WEIGHTENING_KUN_LESUNG_STARTS_WITH_SEARCH);
    }

    private void checkIfLoweredStartsWithLoweredSearch() {
        if (!weighteningFound) checkIfLoweredGermanMeaningStartsWithLoweredSearch();
        if (!weighteningFound) checkIfLoweredOnLesungStartsWithLoweredSearch();
        if (!weighteningFound) checkIfLoweredKunLesungStartsWithLoweredSearch();
    }

    private void checkIfLoweredGermanMeaningStartsWithLoweredSearch() {
        checkIfListElementStartsWithLoweredSearch(loweredGermanMeaningParts,
                WEIGHTENING_LOWERED_GERMAN_MEANING_PART_STARTS_WITH_LOWERED_SEARCH);
    }

    private void checkIfLoweredOnLesungStartsWithLoweredSearch() {
        checkIfListElementStartsWithLoweredSearch(loweredOnLesungen,
                WEIGHTENING_LOWERED_ON_LESUNG_STARTS_WITH_LOWERED_SEARCH);
    }

    private void checkIfLoweredKunLesungStartsWithLoweredSearch() {
        checkIfListElementStartsWithLoweredSearch(loweredKunLesungen,
                WEIGHTENING_LOWERED_KUN_LESUNG_STARTS_WITH_LOWERED_SEARCH);
    }

    private void checkIfEndsWithSearch() {
        if (!weighteningFound) checkIfGermanMeaningEndsWithSearch();
        if (!weighteningFound) checkIfOnLesungEndsWithSearch();
        if (!weighteningFound) checkIfKunLesungEndsWithSearch();
    }

    private void checkIfGermanMeaningEndsWithSearch() {
        checkIfListElementEndsWithSearch(germanMeaningParts,
                WEIGHTENING_GERMAN_MEANING_PART_ENDS_WITH_SEARCH);
    }

    private void checkIfOnLesungEndsWithSearch() {
        checkIfListElementEndsWithSearch(onLesungen, WEIGHTENING_ON_LESUNG_ENDS_WITH_SEARCH);
    }

    private void checkIfKunLesungEndsWithSearch() {
        checkIfListElementEndsWithSearch(kunLesungen, WEIGHTENING_KUN_LESUNG_ENDS_WITH_SEARCH);

    }

    private void checkIfLoweredEndsWithLoweredSearch() {
        if (!weighteningFound) checkIfLoweredGermanMeaningEndsWithLoweredSearch();
        if (!weighteningFound) checkIfLoweredOnLesungEndsWithLoweredSearch();
        if (!weighteningFound) checkIfLoweredKunLesungEndsWithLoweredSearch();
    }

    private void checkIfLoweredGermanMeaningEndsWithLoweredSearch() {
        checkIfListElementEndsWithLoweredSearch(loweredGermanMeaningParts,
                WEIGHTENING_LOWERED_GERMAN_MEANING_PART_ENDS_WITH_LOWERED_SEARCH);
    }

    private void checkIfLoweredOnLesungEndsWithLoweredSearch() {
        checkIfListElementEndsWithLoweredSearch(loweredOnLesungen,
                WEIGHTENING_LOWERED_ON_LESUNG_ENDS_WITH_LOWERED_SEARCH);
    }

    private void checkIfLoweredKunLesungEndsWithLoweredSearch() {
        checkIfListElementEndsWithLoweredSearch(loweredKunLesungen,
                WEIGHTENING_LOWERED_KUN_LESUNG_ENDS_WITH_LOWERED_SEARCH);
    }

    private void checkIfContainsSearchAsSingleWord() {
        if (!weighteningFound) checkIfGermanMeaningContainsSearchAsSingleWord();
        if (!weighteningFound) checkIfOnLesungContainsSearchAsSingleWord();
        if (!weighteningFound) checkIfKunLesungContainsSearchAsSingleWord();
    }

    private void checkIfGermanMeaningContainsSearchAsSingleWord() {
        checkIfListElementContainsSearchAsSingleWord(loweredGermanMeaningParts,
                WEIGHTENING_GERMAN_MEANING_PART_CONTAINS_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfOnLesungContainsSearchAsSingleWord() {
        checkIfListElementContainsSearchAsSingleWord(onLesungen,
                WEIGHTENING_ON_LESUNG_CONTAINS_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfKunLesungContainsSearchAsSingleWord() {
        checkIfListElementContainsSearchAsSingleWord(kunLesungen,
                WEIGHTENING_KUN_LESUNG_CONTAINS_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfContainsLoweredSearchAsLoweredSingleWord() {
        if (!weighteningFound) checkIfLoweredGermanMeaningContainsSearchAsLoweredSingleWord();
        if (!weighteningFound) checkIfLoweredOnLesungContainsSearchAsLoweredSingleWord();
        if (!weighteningFound) checkIfLoweredKunLesungContainsSearchAsLoweredSingleWord();
    }

    private void checkIfLoweredGermanMeaningContainsSearchAsLoweredSingleWord() {
        checkIfListElementContainsLoweredSearchAsSingleWord(loweredGermanMeaningParts,
                WEIGHTENING_LOWERED_GERMAN_MEANING_PART_CONTAINS_LOWERED_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfLoweredOnLesungContainsSearchAsLoweredSingleWord() {
        checkIfListElementContainsLoweredSearchAsSingleWord(loweredOnLesungen,
                WEIGHTENING_LOWERED_ON_LESUNG_CONTAINS_LOWERED_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfLoweredKunLesungContainsSearchAsLoweredSingleWord() {
        checkIfListElementContainsLoweredSearchAsSingleWord(loweredKunLesungen,
                WEIGHTENING_LOWERED_KUN_LESUNG_CONTAINS_LOWERED_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfListElementEqualsSearch(List<String> fieldContents, int weighteningToSet) {
        checkIfListEquals(fieldContents, weighteningToSet, search);
    }

    private void checkIfListElementEqualsLoweredSearch(List<String> fieldContents,
            int weighteningToSet) {
        checkIfListEquals(fieldContents, weighteningToSet, loweredCaseSearch);
    }

    private void checkIfListEquals(List<String> fieldContents, int weighteningToSet,
            String theSearch) {
        for (String fieldContent : fieldContents) {
            if (fieldContent.equals(theSearch)) {
                weighteningFound = true;
                weighting = weighteningToSet;
                return;
            }
        }
    }

    private void checkIfListElementStartsWithSearch(List<String> fieldContents,
            int weighteningToSet) {
        checkIfListStartsWith(fieldContents, weighteningToSet, search);
    }

    private void checkIfListElementStartsWithLoweredSearch(List<String> fieldContents,
            int weighteningToSet) {
        checkIfListStartsWith(fieldContents, weighteningToSet, loweredCaseSearch);
    }

    private void checkIfListStartsWith(List<String> fieldContents, int weighteningToSet,
            String theSearch) {
        for (String fieldContent : fieldContents) {
            if (fieldContent.startsWith(theSearch)) {
                weighteningFound = true;
                weighting = weighteningToSet;
                return;
            }
        }
    }

    private void checkIfListElementEndsWithSearch(List<String> fieldContents,
            int weighteningToSet) {
        checkIfListEndsWith(fieldContents, weighteningToSet, search);
    }

    private void checkIfListElementEndsWithLoweredSearch(List<String> fieldContents,
            int weighteningToSet) {
        checkIfListEndsWith(fieldContents, weighteningToSet, loweredCaseSearch);
    }

    private void checkIfListEndsWith(List<String> fieldContents, int weighteningToSet,
            String theSearch) {
        for (String fieldContent : fieldContents) {
            if (fieldContent.endsWith(theSearch)) {
                weighteningFound = true;
                weighting = weighteningToSet;
                return;
            }
        }
    }

    private void checkIfListElementContainsSearchAsSingleWord(List<String> fieldContents,
            int weighteningToSet) {
        checkIfListContainsAsSingleWord(fieldContents, weighteningToSet, search);
    }

    private void checkIfListElementContainsLoweredSearchAsSingleWord(List<String> fieldContents,
            int weighteningToSet) {
        checkIfListContainsAsSingleWord(fieldContents, weighteningToSet, loweredCaseSearch);
    }

    private void checkIfListContainsAsSingleWord(List<String> fieldContents, int weighteningToSet,
            String theSearch) {
        for (String fieldContent : fieldContents) {
            if (fieldContent.contains(" " + theSearch + " ")) {
                weighteningFound = true;
                weighting = weighteningToSet;
                return;
            }
        }
    }

    /**
     * Getter für die Relevanz der Kanji.
     *
     * Eine höhere Relevanz drückt sich in einer kleineren Zahl aus.
     */
    public int getWeighting() {
        return weighting;
    }

}
