package com.cameleer.server.core.runtime;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class ConfigMerger {

    private ConfigMerger() {}

    public static ResolvedContainerConfig resolve(
            GlobalRuntimeDefaults global,
            Map<String, Object> envConfig,
            Map<String, Object> appConfig) {

        return new ResolvedContainerConfig(
                intVal(appConfig, envConfig, "memoryLimitMb", global.memoryLimitMb()),
                intOrNull(appConfig, envConfig, "memoryReserveMb"),
                intVal(appConfig, envConfig, "cpuRequest", global.cpuRequest()),
                intOrNull(appConfig, envConfig, "cpuLimit"),
                intVal(appConfig, envConfig, "appPort", 8080),
                intList(appConfig, envConfig, "exposedPorts"),
                stringMap(appConfig, envConfig, "customEnvVars"),
                boolVal(appConfig, envConfig, "stripPathPrefix", true),
                boolVal(appConfig, envConfig, "sslOffloading", true),
                stringVal(appConfig, envConfig, "routingMode", global.routingMode()),
                stringVal(appConfig, envConfig, "routingDomain", global.routingDomain()),
                stringVal(appConfig, envConfig, "serverUrl", global.serverUrl()),
                intVal(appConfig, envConfig, "replicas", 1),
                stringVal(appConfig, envConfig, "deploymentStrategy", "blue-green"),
                boolVal(appConfig, envConfig, "routeControlEnabled", true),
                boolVal(appConfig, envConfig, "replayEnabled", true),
                stringVal(appConfig, envConfig, "runtimeType", "auto"),
                stringVal(appConfig, envConfig, "customArgs", ""),
                stringList(appConfig, envConfig, "extraNetworks"),
                boolVal(appConfig, envConfig, "externalRouting", true),
                global.certResolver()
        );
    }

    private static int intVal(Map<String, Object> app, Map<String, Object> env, String key, int fallback) {
        if (app.containsKey(key) && app.get(key) instanceof Number n) return n.intValue();
        if (env.containsKey(key) && env.get(key) instanceof Number n) return n.intValue();
        return fallback;
    }

    private static Integer intOrNull(Map<String, Object> app, Map<String, Object> env, String key) {
        if (app.containsKey(key) && app.get(key) instanceof Number n) return n.intValue();
        if (env.containsKey(key) && env.get(key) instanceof Number n) return n.intValue();
        return null;
    }

    private static Double doubleOrNull(Map<String, Object> app, Map<String, Object> env, String key) {
        if (app.containsKey(key) && app.get(key) instanceof Number n) return n.doubleValue();
        if (env.containsKey(key) && env.get(key) instanceof Number n) return n.doubleValue();
        return null;
    }

    private static boolean boolVal(Map<String, Object> app, Map<String, Object> env, String key, boolean fallback) {
        if (app.containsKey(key) && app.get(key) instanceof Boolean b) return b;
        if (env.containsKey(key) && env.get(key) instanceof Boolean b) return b;
        return fallback;
    }

    private static String stringVal(Map<String, Object> app, Map<String, Object> env, String key, String fallback) {
        if (app.containsKey(key) && app.get(key) instanceof String s) return s;
        if (env.containsKey(key) && env.get(key) instanceof String s) return s;
        return fallback;
    }

    @SuppressWarnings("unchecked")
    private static List<Integer> intList(Map<String, Object> app, Map<String, Object> env, String key) {
        Object val = app.containsKey(key) ? app.get(key) : env.get(key);
        if (val instanceof List<?> list) {
            return list.stream()
                    .filter(Number.class::isInstance)
                    .map(n -> ((Number) n).intValue())
                    .toList();
        }
        return List.of();
    }

    private static List<String> stringList(Map<String, Object> app, Map<String, Object> env, String key) {
        Object val = app.containsKey(key) ? app.get(key) : env.get(key);
        if (val instanceof List<?> list) {
            return list.stream()
                    .filter(String.class::isInstance)
                    .map(String.class::cast)
                    .toList();
        }
        return List.of();
    }

    @SuppressWarnings("unchecked")
    private static Map<String, String> stringMap(Map<String, Object> app, Map<String, Object> env, String key) {
        Object val = app.containsKey(key) ? app.get(key) : env.get(key);
        if (val instanceof Map<?, ?> map) {
            Map<String, String> result = new HashMap<>();
            map.forEach((k, v) -> result.put(String.valueOf(k), String.valueOf(v)));
            return Collections.unmodifiableMap(result);
        }
        return Map.of();
    }

    /** Global defaults extracted from application.yml @Value fields */
    public record GlobalRuntimeDefaults(
            int memoryLimitMb,
            int cpuRequest,
            String routingMode,
            String routingDomain,
            String serverUrl,
            String certResolver
    ) {}
}
