package de.gecheckt.pdf.umbenenner.application.port.out.modelcatalog;

import java.util.Objects;
import java.util.Optional;

/**
 * Describes the provenance of the effective API key for a provider, including the name of the
 * environment variable that supplies the key when applicable.
 * <p>
 * The GUI uses this record to display provenance information to the user (e.g., "Schlüssel
 * kommt aus Umgebungsvariable ANTHROPIC_API_KEY") without coupling the display logic to the
 * concrete variable names.
 * <p>
 * The {@code envVarName} field is present when the origin is
 * {@link ApiKeyOrigin#FROM_PROVIDER_ENV_VAR} or {@link ApiKeyOrigin#FROM_LEGACY_ENV_VAR};
 * it is absent for {@link ApiKeyOrigin#FROM_PROPERTY_FILE} and {@link ApiKeyOrigin#ABSENT}.
 *
 * @param origin      the source from which the effective key value comes; never {@code null}
 * @param envVarName  the name of the environment variable that provides the key when applicable;
 *                    empty when the origin is {@code FROM_PROPERTY_FILE} or {@code ABSENT}
 */
public record EffectiveApiKeyDescriptor(
        ApiKeyOrigin origin,
        Optional<String> envVarName) {

    /**
     * Creates a new descriptor.
     *
     * @param origin     key origin; must not be {@code null}
     * @param envVarName optional environment variable name; {@code null} becomes empty
     * @throws NullPointerException if {@code origin} is {@code null}
     */
    public EffectiveApiKeyDescriptor {
        Objects.requireNonNull(origin, "origin must not be null");
        envVarName = Objects.requireNonNullElse(envVarName, Optional.empty());
    }

    /**
     * Creates a descriptor for a key that comes from a provider-specific environment variable.
     *
     * @param variableName the name of the environment variable; must not be {@code null}
     * @return a new descriptor with origin {@link ApiKeyOrigin#FROM_PROVIDER_ENV_VAR}
     * @throws NullPointerException if {@code variableName} is {@code null}
     */
    public static EffectiveApiKeyDescriptor fromProviderEnvVar(String variableName) {
        Objects.requireNonNull(variableName, "variableName must not be null");
        return new EffectiveApiKeyDescriptor(ApiKeyOrigin.FROM_PROVIDER_ENV_VAR,
                Optional.of(variableName));
    }

    /**
     * Creates a descriptor for a key that comes from the legacy environment variable.
     *
     * @param variableName the name of the legacy environment variable; must not be {@code null}
     * @return a new descriptor with origin {@link ApiKeyOrigin#FROM_LEGACY_ENV_VAR}
     * @throws NullPointerException if {@code variableName} is {@code null}
     */
    public static EffectiveApiKeyDescriptor fromLegacyEnvVar(String variableName) {
        Objects.requireNonNull(variableName, "variableName must not be null");
        return new EffectiveApiKeyDescriptor(ApiKeyOrigin.FROM_LEGACY_ENV_VAR,
                Optional.of(variableName));
    }

    /**
     * Creates a descriptor for a key that comes from the properties file.
     *
     * @return a new descriptor with origin {@link ApiKeyOrigin#FROM_PROPERTY_FILE}
     */
    public static EffectiveApiKeyDescriptor fromPropertyFile() {
        return new EffectiveApiKeyDescriptor(ApiKeyOrigin.FROM_PROPERTY_FILE, Optional.empty());
    }

    /**
     * Creates a descriptor indicating that no key value is available.
     *
     * @return a new descriptor with origin {@link ApiKeyOrigin#ABSENT}
     */
    public static EffectiveApiKeyDescriptor absent() {
        return new EffectiveApiKeyDescriptor(ApiKeyOrigin.ABSENT, Optional.empty());
    }

    /**
     * Returns {@code true} when the effective key comes from any environment variable.
     *
     * @return {@code true} for {@link ApiKeyOrigin#FROM_PROVIDER_ENV_VAR} and
     *         {@link ApiKeyOrigin#FROM_LEGACY_ENV_VAR}
     */
    public boolean isFromEnvironmentVariable() {
        return origin == ApiKeyOrigin.FROM_PROVIDER_ENV_VAR
                || origin == ApiKeyOrigin.FROM_LEGACY_ENV_VAR;
    }

    /**
     * Returns {@code true} when no key is available from any source.
     *
     * @return {@code true} for {@link ApiKeyOrigin#ABSENT}
     */
    public boolean isAbsent() {
        return origin == ApiKeyOrigin.ABSENT;
    }
}
