package de.gecheckt.pdf.umbenenner.adapter.in.gui.editor;

import java.util.LinkedHashMap;
import java.util.Map;

import de.gecheckt.pdf.umbenenner.application.config.provider.AiProviderFamily;

/**
 * Merges the current editor API-key values against the baseline values before a file
 * is written to disk.
 * <p>
 * The merge rule is:
 * <ul>
 *   <li>When a provider's API-key field is non-empty in the current editor values, the
 *       current value is kept unchanged.</li>
 *   <li>When a provider's API-key field is empty in the current editor values but the
 *       corresponding baseline field holds a non-empty value, the baseline value is
 *       carried into the merged result so the key is not silently deleted from the
 *       written file.</li>
 *   <li>When both the current and the baseline value are empty, no preservation occurs
 *       and the merged result also contains an empty value.</li>
 * </ul>
 *
 * <p>The result indicates which provider (if any) triggered a preservation event so the
 * GUI can display a warning via later validation layers without coupling the write path
 * to the warning display mechanism.
 */
public final class GuiApiKeyMerger {

    private GuiApiKeyMerger() {
        // Utility class.
    }

    /**
     * Merges the API-key values from the given editor state and returns both the merged
     * values and the first provider identifier for which a key was silently preserved.
     *
     * @param state the current editor state; must not be {@code null}
     * @return the merge result; never {@code null}
     */
    public static MergeResult merge(GuiConfigurationEditorState state) {
        return merge(state.values(), state.baselineValues());
    }

    /**
     * Merges the API-key values from the given current and baseline configuration values.
     *
     * @param current  the current editor values; must not be {@code null}
     * @param baseline the baseline values to compare against; must not be {@code null}
     * @return the merge result; never {@code null}
     */
    public static MergeResult merge(GuiConfigurationValues current, GuiConfigurationValues baseline) {
        Map<AiProviderFamily, GuiProviderConfigurationState> merged = new LinkedHashMap<>(
                current.providerConfigurations());

        String preservedProvider = null;

        for (AiProviderFamily family : AiProviderFamily.values()) {
            GuiProviderConfigurationState currentProvider = current.providerConfiguration(family);
            if (currentProvider == null) {
                continue;
            }
            String editorKey = currentProvider.apiKey().propertyValue();
            if (!editorKey.isBlank()) {
                continue;
            }
            GuiProviderConfigurationState baselineProvider = baseline.providerConfiguration(family);
            if (baselineProvider == null) {
                continue;
            }
            String baselineKey = baselineProvider.apiKey().propertyValue();
            if (baselineKey != null && !baselineKey.isBlank()) {
                merged.put(family, new GuiProviderConfigurationState(
                        currentProvider.baseUrl(),
                        currentProvider.model(),
                        currentProvider.timeoutSeconds(),
                        GuiProviderApiKeyState.unresolved(baselineKey)));
                if (preservedProvider == null) {
                    preservedProvider = family.getIdentifier();
                }
            }
        }

        GuiConfigurationValues mergedValues = new GuiConfigurationValues(
                current.sourceFolder(),
                current.targetFolder(),
                current.sqliteFile(),
                current.promptTemplateFile(),
                current.runtimeLockFile(),
                current.logDirectory(),
                current.logLevel(),
                current.maxRetriesTransient(),
                current.maxPages(),
                current.maxTextCharacters(),
                current.maxTitleLength(),
                current.logAiSensitive(),
                current.activeProviderFamily(),
                merged);

        return new MergeResult(mergedValues, preservedProvider);
    }

    /**
     * Result of an API-key merge operation.
     *
     * @param values                    the merged configuration values; never {@code null}
     * @param preservedProviderIdentifier provider identifier when a key was preserved from
     *                                   the baseline; {@code null} when no preservation occurred
     */
    public record MergeResult(GuiConfigurationValues values, String preservedProviderIdentifier) {

        /**
         * Returns whether at least one provider API key was silently preserved.
         *
         * @return {@code true} when a preservation event occurred
         */
        public boolean hasPreservationNote() {
            return preservedProviderIdentifier != null;
        }
    }
}
