package com.cameleer.server.app.config;

import com.cameleer.server.app.storage.PostgresAppRepository;
import com.cameleer.server.app.storage.PostgresAppVersionRepository;
import com.cameleer.server.app.storage.PostgresDeploymentRepository;
import com.cameleer.server.app.storage.PostgresEnvironmentRepository;
import com.cameleer.server.core.runtime.AppRepository;
import com.cameleer.server.core.runtime.AppService;
import com.cameleer.server.core.runtime.AppVersionRepository;
import com.cameleer.server.core.runtime.DeploymentRepository;
import com.cameleer.server.core.runtime.DeploymentService;
import com.cameleer.server.core.runtime.DirtyStateCalculator;
import com.cameleer.server.core.runtime.EnvironmentRepository;
import com.cameleer.server.core.runtime.EnvironmentService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

/**
 * Creates runtime management beans: repositories, services, and async executor.
 * <p>
 * Follows the established pattern: core module plain class, app module bean config.
 */
@Configuration
public class RuntimeBeanConfig {

    @Bean
    public EnvironmentRepository environmentRepository(JdbcTemplate jdbc, ObjectMapper objectMapper) {
        return new PostgresEnvironmentRepository(jdbc, objectMapper);
    }

    @Bean
    public AppRepository appRepository(JdbcTemplate jdbc, ObjectMapper objectMapper) {
        return new PostgresAppRepository(jdbc, objectMapper);
    }

    @Bean
    public AppVersionRepository appVersionRepository(JdbcTemplate jdbc) {
        return new PostgresAppVersionRepository(jdbc);
    }

    @Bean
    public DeploymentRepository deploymentRepository(JdbcTemplate jdbc, ObjectMapper objectMapper) {
        return new PostgresDeploymentRepository(jdbc, objectMapper);
    }

    @Bean
    public EnvironmentService environmentService(EnvironmentRepository repo,
                                                 com.cameleer.server.app.license.LicenseEnforcer enforcer) {
        return new EnvironmentService(repo, current ->
                enforcer.assertWithinCap("max_environments", current, 1));
    }

    @Bean
    public AppService appService(AppRepository appRepo, AppVersionRepository versionRepo,
                                  @Value("${cameleer.server.runtime.jarstoragepath:/data/jars}") String jarStoragePath,
                                  com.cameleer.server.app.license.LicenseEnforcer enforcer) {
        return new AppService(appRepo, versionRepo, jarStoragePath,
                current -> enforcer.assertWithinCap("max_apps", current, 1));
    }

    @Bean
    public DeploymentService deploymentService(DeploymentRepository deployRepo, AppService appService, EnvironmentService envService) {
        return new DeploymentService(deployRepo, appService, envService);
    }

    @Bean
    public DirtyStateCalculator dirtyStateCalculator(ObjectMapper objectMapper) {
        return new DirtyStateCalculator(objectMapper);
    }

    @Bean(name = "deploymentTaskExecutor")
    public Executor deploymentTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(4);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("deploy-");
        executor.initialize();
        return executor;
    }
}
