/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.trino.tests.product.launcher.env;

import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.google.inject.multibindings.MapBinder;
import io.trino.tests.product.launcher.env.common.Hadoop;
import io.trino.tests.product.launcher.env.common.HadoopKerberos;
import io.trino.tests.product.launcher.env.common.HadoopKerberosKms;
import io.trino.tests.product.launcher.env.common.HydraIdentityProvider;
import io.trino.tests.product.launcher.env.common.Kafka;
import io.trino.tests.product.launcher.env.common.SeleniumChrome;
import io.trino.tests.product.launcher.env.common.Standard;
import io.trino.tests.product.launcher.env.common.StandardMultinode;
import io.trino.tests.product.launcher.testcontainers.PortBinder;

import java.io.File;

import static com.google.inject.Scopes.SINGLETON;
import static com.google.inject.multibindings.MapBinder.newMapBinder;
import static io.trino.tests.product.launcher.env.Environments.nameForConfigClass;
import static java.util.Objects.requireNonNull;
import static java.util.Objects.requireNonNullElse;

public final class EnvironmentModule
        implements Module
{
    public static final String BASE_PACKAGE = "io.trino.tests.product.launcher.env.environment";
    public static final String BASE_CONFIG_PACKAGE = "io.trino.tests.product.launcher.env.configs";
    private final EnvironmentOptions environmentOptions;
    private final Module additionalEnvironments;

    public EnvironmentModule(EnvironmentOptions environmentOptions, Module additionalEnvironments)
    {
        this.environmentOptions = requireNonNull(environmentOptions, "environmentOptions is null");
        this.additionalEnvironments = requireNonNull(additionalEnvironments, "additionalEnvironments is null");
    }

    @Override
    public void configure(Binder binder)
    {
        binder.bind(PortBinder.class).in(SINGLETON);
        binder.bind(EnvironmentFactory.class).in(SINGLETON);
        binder.bind(EnvironmentConfigFactory.class).in(SINGLETON);
        binder.bind(EnvironmentOptions.class).toInstance(environmentOptions);

        binder.bind(Hadoop.class).in(SINGLETON);
        binder.bind(HadoopKerberos.class).in(SINGLETON);
        binder.bind(HadoopKerberosKms.class).in(SINGLETON);
        binder.bind(HydraIdentityProvider.class).in(SINGLETON);
        binder.bind(Kafka.class).in(SINGLETON);
        binder.bind(SeleniumChrome.class).in(SINGLETON);
        binder.bind(Standard.class).in(SINGLETON);
        binder.bind(StandardMultinode.class).in(SINGLETON);

        MapBinder<String, EnvironmentProvider> environments = newMapBinder(binder, String.class, EnvironmentProvider.class);
        Environments.findByBasePackage(BASE_PACKAGE).forEach(clazz -> environments.addBinding(Environments.nameForClass(clazz)).to(clazz).in(SINGLETON));

        MapBinder<String, EnvironmentConfig> environmentConfigs = newMapBinder(binder, String.class, EnvironmentConfig.class);
        Environments.findConfigsByBasePackage(BASE_CONFIG_PACKAGE).forEach(clazz -> environmentConfigs.addBinding(nameForConfigClass(clazz)).to(clazz).in(SINGLETON));

        binder.install(additionalEnvironments);
    }

    @Provides
    @Singleton
    public EnvironmentConfig provideEnvironmentConfig(EnvironmentOptions options, EnvironmentConfigFactory factory)
    {
        return factory.getConfig(options.config);
    }

    @Provides
    @Singleton
    @ServerPackage
    public File provideServerPackage(EnvironmentOptions options)
    {
        // fallback to dummy - nonNull to prevent injection errors when listing environments
        return requireNonNullElse(options.serverPackage, new File("dummy.tar.gz"));
    }

    @Provides
    @Singleton
    @Debug
    public boolean provideDebug(EnvironmentOptions options)
    {
        return options.debug;
    }
}

@@ -1765,29 +1765,30 @@
 dule%0A%7B%0A    p
-ublic
+rivate
  static fina
@@ -1796,20 +1796,24 @@
  String 
-BASE
+LAUNCHER
 _PACKAGE
@@ -1843,24 +1843,101 @@
 uct.launcher
+%22;%0A    private static final String ENVIRONMENT_PACKAGE = LAUNCHER_PACKAGE + %22
 .env.environ
@@ -1948,21 +1948,22 @@
 %22;%0A    p
-ublic
+rivate
  static 
@@ -1975,21 +1975,16 @@
  String 
-BASE_
 CONFIG_P
@@ -1996,40 +1996,28 @@
 E = 
-%22io.trino.tests.product.launcher
+LAUNCHER_PACKAGE + %22
 .env
@@ -3390,20 +3390,27 @@
 Package(
-BASE
+ENVIRONMENT
 _PACKAGE
@@ -3690,13 +3690,8 @@
 age(
-BASE_
 CONF

Refactor constants