package de.duehl.basics.system.launcher;

/*
 * Copyright 2025 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import de.duehl.basics.collections.CollectionsHelper;
import de.duehl.basics.io.FileHelper;
import de.duehl.basics.system.SystemTools;
import de.duehl.basics.system.launcher.data.JarWithVersion;
import de.duehl.basics.version.Version;

/**
 * Diese Klasse ermittelt die neuste Version einer von ggf. mehreren Jars mit dem gleichen Namen
 * aber unterschiedlichen Versionen.
 *
 * Gesucht wird im 'current working directory', also dort, von wo dieses laufende Programm
 * gestartet worden ist.
 *
 * Optional kann sie alle alten Jars löschen.
 *
 * Sie kann in Launcher wie z.B. dem des Vokabeltrainers verwendet werden.
 *
 * @version 1.01     2025-09-01
 * @author Christian Dühl
 */

public class NewestJarDeterminer {

    /** Der Anfang der Datei-Namen (ohne Pfad) der zu suchenden Jar-Dateien. */
    private final String jarNameStart;

    /** Das aktuelle Arbeitsverzeichnis (current working directory). */
    private final String currentWorkingDirectory;

    /** Gibt an, ob die alten Jars entfernt werden sollen. */
    private boolean removeOldJars;

    /** Gibt an, ob die Jar gefunden werden konnte. */
    private boolean jarFound;

    /** Der Name der neusten Jar-Datei mit Pfad. */
    private String newestJarFilename;

    /**
     * Konstruktor.
     *
     * @param jarNameStart
     *            Der Anfang der Datei-Namen (ohne Pfad) der zu suchenden Jar-Dateien.
     */
    public NewestJarDeterminer(String jarNameStart) {
        this.jarNameStart = jarNameStart;
        currentWorkingDirectory = SystemTools.getCurrentWorkingDirectory();
        removeOldJars = false;
    }

    /** Legt fest, dass  die alten Jars entfernt werden sollen. */
    public void removeOldJars() {
        removeOldJars = true;
    }

    /** Führt die Bestimmung der neusten Jar-Datei durch. */
    public void determine() {
        List<String> jarFilenames = findJarFiles();

        if (jarFilenames.isEmpty()) {
            jarFound = false;
            newestJarFilename = "";
        }
        else if (jarFilenames.size() == 1) {
            jarFound = true;
            newestJarFilename = jarFilenames.get(0);
        }
        else {
            List<JarWithVersion> jarsWithVersions = createJarsWithVersions(jarFilenames);
            if (jarsWithVersions.size() != jarFilenames.size()) {
                throw new RuntimeException("Die erzeugte Liste mit den Jars und Versionsnummern\n"
                        + "hat nicht die gleiche Größe wie die Liste der Dateinamen der Jars.\n"
                        + "\t" + "jarFilenames.size()     = " + jarFilenames.size() + "\n"
                        + "\t" + "jarsWithVersions.size() = " + jarsWithVersions.size() + "\n"
                        + "jarFilenames:\n"
                        + CollectionsHelper.listListNiceWithoutBrackets(jarFilenames)
                        + "jarsWithVersions:\n"
                        + CollectionsHelper.listListNiceWithoutBrackets(jarsWithVersions)
                        );
            }
            sortJarsWithVersionsByVersion(jarsWithVersions);
            JarWithVersion jarWithHighestVersion =
                    jarsWithVersions.get(jarsWithVersions.size() - 1); // TODO Java 21
            jarFound = true;
            newestJarFilename = jarWithHighestVersion.getJarFilename();
            if (removeOldJars) {
                jarFilenames.remove(newestJarFilename);
                FileHelper.deleteFilesPrintErrors(jarFilenames);
            }
        }
    }

    private List<String> findJarFiles() {
        return FileHelper.findFilesInMainDirectoryNio2(currentWorkingDirectory, jarNameStart,
                ".jar");
    }

    private List<JarWithVersion> createJarsWithVersions(List<String> jarFilenames) {
        List<JarWithVersion> jarsWithVersions = new ArrayList<>();

        for (String jarFilename : jarFilenames) {
            String version = Version.extractVersionFromJarFilename(jarFilename, jarNameStart);
            JarWithVersion jarWithVersion = new JarWithVersion();
            jarWithVersion.setJarFilename(jarFilename);
            jarWithVersion.setVersion(version);
            jarsWithVersions.add(jarWithVersion);
        }

        return jarsWithVersions;
    }

    /** Wir sortieren von kleiner Version zu großer Version, also von alter zu neuer. */
    private void sortJarsWithVersionsByVersion(List<JarWithVersion> jarsWithVersions) {
        Collections.sort(jarsWithVersions, new Comparator<JarWithVersion>() {
            @Override
            public int compare(JarWithVersion j1, JarWithVersion j2) {
                String versionString1 = j1.getVersion();
                String versionString2 = j2.getVersion();
                Version version1 = new Version(versionString1, "interessiert nicht");
                Version version2 = new Version(versionString2, "interessiert nicht");
                if (version1.isNewerThan(version2)) {
                    return 1;
                }
                else if (version2.isNewerThan(version1)) {
                    return -1;
                }
                else {
                    return 0;
                }
            }
        });
    }

    /** Gibt an, ob die Jar gefunden werden konnte. */
    public boolean isJarFound() {
        return jarFound;
    }

    /** Getter für den Namen der neusten Jar-Datei mit Pfad. */
    public String getNewestJarFilename() {
        return newestJarFilename;
    }

}
