package de.gecheckt.pdf.umbenenner.bootstrap;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import de.gecheckt.pdf.umbenenner.bootstrap.startup.CliArgumentParser;
import de.gecheckt.pdf.umbenenner.bootstrap.startup.EarlyLogDirectoryInitializer;
import de.gecheckt.pdf.umbenenner.bootstrap.startup.StartupArguments;
import de.gecheckt.pdf.umbenenner.bootstrap.startup.StartupArgumentsParseResult;

/**
 * Main entry point for the PDF Umbenenner application.
 * <p>
 * Responsible for:
 * <ol>
 *   <li>Parsing raw command-line arguments via {@link CliArgumentParser}.</li>
 *   <li>Aborting with exit code 1 when the arguments are invalid or unrecognised.</li>
 *   <li>Delegating to {@link BootstrapRunner} for startup mode selection,
 *       object graph construction, and execution.</li>
 * </ol>
 * <p>
 * Supported CLI options:
 * <ul>
 *   <li>(none) — GUI startup mode (default).</li>
 *   <li>{@code --headless} — Headless batch/scheduler startup mode.</li>
 *   <li>{@code --config <path>} — Override for the configuration file path,
 *       applicable to both startup modes.</li>
 * </ul>
 */
public class PdfUmbenennerApplication {

    /**
     * Application entry point.
     * <p>
     * Parses the command-line arguments and delegates to {@link BootstrapRunner}.
     * If the arguments cannot be parsed, an error is logged and the process exits
     * with code 1 before any further initialisation takes place.
     * <p>
     * Vor jeder Logger-Nutzung wird {@link EarlyLogDirectoryInitializer} aufgerufen,
     * damit die Property {@code log.directory} aus der aktiven Konfigurationsdatei
     * bereits vor der einmaligen Log4j2-Initialisierung gesetzt ist.
     *
     * @param args command-line arguments; see class JavaDoc for supported options
     */
    public static void main(String[] args) {
        EarlyLogDirectoryInitializer.LogDirectorySetupResult logSetup =
                EarlyLogDirectoryInitializer.applyFromArgs(args);
        Logger LOG = LogManager.getLogger(PdfUmbenennerApplication.class);
        LOG.info("Starting PDF Umbenenner application...");
        logEffectiveLogDirectory(LOG, logSetup);
        try {
            StartupArgumentsParseResult parseResult = new CliArgumentParser().parse(args);

            if (parseResult instanceof StartupArgumentsParseResult.Invalid invalid) {
                LOG.error("Invalid command-line arguments: {}", invalid.errorMessage());
                System.exit(1);
                return;
            }

            StartupArguments startupArguments =
                    ((StartupArgumentsParseResult.Valid) parseResult).arguments();
            LOG.info("Startup mode: {}", startupArguments.mode());
            startupArguments.configPath().ifPresent(
                    p -> LOG.info("Configuration path override: {}", p));

            BootstrapRunner runner = new BootstrapRunner();
            int exitCode = runner.run(startupArguments);
            if (exitCode == 0) {
                LOG.info("PDF Umbenenner application completed successfully.");
            } else {
                LOG.error("PDF Umbenenner application terminated with error code {}.", exitCode);
            }
            System.exit(exitCode);
        } catch (Exception e) {
            LOG.fatal("Unexpected technical bootstrap failure in PDF Umbenenner application.", e);
            System.exit(1);
        }
    }

    /**
     * Protokolliert nach der Log4j2-Initialisierung sichtbar, welches Log-Verzeichnis
     * effektiv genutzt wird.
     * <p>
     * Musste die Anwendung wegen eines nicht anlegbaren konfigurierten Verzeichnisses auf
     * das Standard-Log-Verzeichnis ausweichen, wird dies als Warnung mit konfiguriertem und
     * tatsächlichem Pfad ausgegeben, damit der frühere stille Fehlschlag nachvollziehbar ist.
     * Diese erste Logzeile landet im effektiv genutzten Log und macht den Speicherort auffindbar.
     *
     * @param log      der bereits initialisierte Logger; darf nicht {@code null} sein
     * @param logSetup das Ergebnis der frühen Log-Verzeichnis-Auflösung; darf nicht {@code null} sein
     */
    private static void logEffectiveLogDirectory(Logger log,
            EarlyLogDirectoryInitializer.LogDirectorySetupResult logSetup) {
        String fallbackDirectory = System.getProperty("user.home") + "/pdf-umbenenner/logs";
        if (logSetup.fallbackUsed()) {
            log.warn("Konfiguriertes Log-Verzeichnis '{}' konnte nicht angelegt oder genutzt werden – "
                    + "Ausweichen auf Standard-Log-Verzeichnis '{}'.",
                    logSetup.configuredValue(), fallbackDirectory);
        } else if (logSetup.appliedDirectory() != null) {
            log.info("Effektives Log-Verzeichnis: {}", logSetup.appliedDirectory());
        } else {
            log.info("Kein Log-Verzeichnis konfiguriert – Standard-Log-Verzeichnis '{}' wird genutzt.",
                    fallbackDirectory);
        }
    }
}
