package de.duehl.vocabulary.japanese.io;

import java.util.ArrayList;
import java.util.List;

import de.duehl.basics.io.Charset;
import de.duehl.basics.io.FileHelper;
import de.duehl.basics.text.Text;
import de.duehl.basics.text.definitions.DefinitionLineParser;
import de.duehl.vocabulary.japanese.data.Vocable;

/**
 * Diese Klasse liest eine Datei mit Vokabeln ein.
 *
 * @version 1.01     2025-08-04
 * @author Christian Dühl
 */

public class VocabularyReader {

    private static final String VOCABULARY_CATEGORY_KEY = "vocabulary-category";
    private static final String VOCABULARY_SUB_CATEGORY_KEY = "vocabulary-sub-category";

    private static final String DEFAULT_VOCABULARY_CATEGORY = "Default";
    private static final String DEFAULT_VOCABULARY_SUB_CATEGORY = "Default";

    private static final String STOP_READING = "__BIS_HIER__";


    /** Der Name der Datei mit den Vokabeln mit Pfad. */
    private final String filename;

    /** Die Liste der eingelesenen Zeilen. */
    private List<String> lines;

    /** Die Liste der eingelesenen Vokabeln. */
    private List<Vocable> vocables;

    /** Die Kategorie zu der das Vokabular gehört. */
    private String vocabularyCategory;

    /** Die Unterkategorie zu der das Vokabular gehört. */
    private String vocabularySubCategory;

    /**
     * Konstruktor.
     *
     * @param filename
     *            Der Name der Datei mit den Vokabeln mit Pfad.
     */
    public VocabularyReader(String filename) {
        this.filename = filename;

        vocabularyCategory = DEFAULT_VOCABULARY_CATEGORY;
        vocabularySubCategory = DEFAULT_VOCABULARY_SUB_CATEGORY;
    }

    /** Führt das Einlesen durch. */
    public void read() {
        readLinesOfVocabularyFile();
        parseVocables();
    }

    private void readLinesOfVocabularyFile() {
        lines = FileHelper.readFileToList(filename, Charset.UTF_8);
    }

    private void parseVocables() {
        vocables = new ArrayList<>();

        boolean inVocable = false;
        Vocable vocable = null;

        for (String line : lines) {
            if (line.equals(STOP_READING)) {
                break;
            }
            if (line.startsWith("#")) {
                continue;
            }
            if (line.startsWith(VOCABULARY_CATEGORY_KEY)) {
                parseVocabularyCategory(line);
            }
            else if (line.startsWith(VOCABULARY_SUB_CATEGORY_KEY)) {
                parseVocabularySubCategory(line);
            }
            else {
                if (line.isBlank()) {
                    if (inVocable) {
                        vocables.add(vocable);
                        inVocable = false;
                    }
                }
                else {
                    if (!inVocable) {
                        vocable = new Vocable();
                        inVocable = true;
                    }
                    parseLineAndAddToVocable(line, vocable);
                }
            }
        }

        if (inVocable) {
            vocables.add(vocable);
            inVocable = false;
        }
    }

    private void parseVocabularyCategory(String line) {
        DefinitionLineParser parser = new DefinitionLineParser(line, filename);
        parser.parse();
        String key = parser.getKey();
        String value = parser.getValue();
        if (!key.equalsIgnoreCase(VOCABULARY_CATEGORY_KEY)) {
            throw new RuntimeException(""
                  + "Die Zeile mit der Kategorie des Vokabulars enthält den falschen Schlüssel.\n"
                  + "\t" + "filename = '" + filename + "'.\n"
                  + "\t" + "Zeile    = '" + line + "'.\n"
                  + "\t" + "key      = '" + key + "'.\n"
                  + "\t" + "erwartet = '" + VOCABULARY_CATEGORY_KEY + "'.\n"
                  + "Die Groß-/Kleinschreibung spielt keine Rolle.");
        }
        if (vocabularyCategory.equals(DEFAULT_VOCABULARY_CATEGORY)) {
            vocabularyCategory = value;
        }
        else {
            throw new RuntimeException(""
                    + "Es gibt mehr als eine Kategorie des Vokabulars.\n"
                    + "\t" + "filename   = '" + filename + "'.\n"
                    + "\t" + "Kategorie1 = '" + vocabularyCategory + "'.\n"
                    + "\t" + "Kategorie2 = '" + value + "'.\n");
        }
    }

    private void parseVocabularySubCategory(String line) {
        DefinitionLineParser parser = new DefinitionLineParser(line, filename);
        parser.parse();
        String key = parser.getKey();
        String value = parser.getValue();
        if (!key.equalsIgnoreCase(VOCABULARY_SUB_CATEGORY_KEY)) {
            throw new RuntimeException(""
                  + "Die Zeile mit der Unterkategorie des Vokabulars enthält den falschen Schlüssel.\n"
                  + "\t" + "filename = '" + filename + "'.\n"
                  + "\t" + "Zeile    = '" + line + "'.\n"
                  + "\t" + "key      = '" + key + "'.\n"
                  + "\t" + "erwartet = '" + VOCABULARY_SUB_CATEGORY_KEY + "'.\n"
                  + "Die Groß-/Kleinschreibung spielt keine Rolle.");
        }
        if (vocabularySubCategory.equals(DEFAULT_VOCABULARY_SUB_CATEGORY)) {
            vocabularySubCategory = value;
        }
        else {
            throw new RuntimeException(""
                    + "Es gibt mehr als eine Unterkategorie des Vokabulars.\n"
                    + "\t" + "filename        = '" + filename + "'.\n"
                    + "\t" + "Unterkategorie1 = '" + vocabularySubCategory + "'.\n"
                    + "\t" + "Unterkategorie2 = '" + value + "'.\n");
        }
    }

    private void parseLineAndAddToVocable(String line, Vocable vocable) {
        DefinitionLineParser parser = new DefinitionLineParser(line, filename);
        parser.parse();
        String key = parser.getKey();
        String value = parser.getValue();
        addToVocable(key, value, vocable);
    }

    private void addToVocable(String key, String value, Vocable vocable) {
        if (key.equals("kana")) {
            checkEmptyValue(key, value, vocable);
            vocable.setKana(value);
        }
        else if (key.equals("kanji")) {
            vocable.setKanji(value);
        }
        else if (key.equals("romaji")) {
            checkEmptyValue(key, value, vocable);
            vocable.setRomaji(value);
        }
        else if (key.equals("aussprache")) {
            checkEmptyValue(key, value, vocable);
            vocable.setPronunciation(value);
        }
        else if (key.startsWith("deutsch")) {
            checkEmptyValue(key, value, vocable);
            vocable.addToTranslations(value);
        }
        else if (key.equals("mp3")) {
            checkEmptyValue(key, value, vocable);
            vocable.setBareMp3(value);
        }
        else if (key.equals("bemerkung")) {
            vocable.setComment(value);
        }
        else if (key.equals("suchbegriffe")) {
            List<String> searchWords = Text.splitByKomma(value);
            vocable.setSearchWords(searchWords);
        }
        else if (key.equals("wortart") || key.equals("wortarten")) {
            List<String> partsOfSpeach = Text.splitByKomma(value);
            vocable.setPartsOfSpeech(partsOfSpeach);
        }
        else {
            throw new RuntimeException("Unbekannter Schlüssel.\n"
                    + "\t" + "filename = '" + filename + "'.\n"
                    + "\t" + "key      = '" + key + "'.\n"
                    + "\t" + "vocable  = '" + vocable + "'.\n");
        }
    }

    private void checkEmptyValue(String key, String value, Vocable vocable) {
        if (value.isBlank()) {
            throw new RuntimeException(""
                    + "Der Wert zum Schlüssel ist leer.\n"
                    + "\t" + "filename = '" + filename + "'.\n"
                    + "\t" + "key      = '" + key + "'.\n"
                    + "\t" + "vocable  = '" + vocable + "'.\n");
        }
    }

    /** Getter für die Liste der eingelesenen Vokabeln. */
    public List<Vocable> getVocables() {
        return vocables;
    }

    /** Getter für die Kategorie zu der das Vokabular gehört. */
    public String getVocabularyCategory() {
        return vocabularyCategory;
    }

    /** Getter für die Unterkategorie zu der das Vokabular gehört. */
    public String getVocabularySubCategory() {
        return vocabularySubCategory;
    }

}
