package com.iqser.red.service.peristence.v1.server.integration.utils;

import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.Set;

import org.jetbrains.annotations.NotNull;
import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
import org.testcontainers.utility.DockerImageName;

public class KneconSpringPostgreSQLTestContainer extends JdbcDatabaseContainer<KneconSpringPostgreSQLTestContainer> {

    private static final String IMAGE_VERSION = "nexus.knecon.com:5001/bitnami/postgresql:14.5.0-debian-11-r31";
    private static KneconSpringPostgreSQLTestContainer container;


    private KneconSpringPostgreSQLTestContainer() {

        super(IMAGE_VERSION);
    }


    public static KneconSpringPostgreSQLTestContainer getInstance() {

        if (container == null) {
            container = new KneconSpringPostgreSQLTestContainer(DockerImageName.parse(IMAGE_VERSION));
        }
        return container;
    }


    public static final Integer POSTGRESQL_PORT = 5432;
    private String databaseName;
    private String username;
    private String password;


    public KneconSpringPostgreSQLTestContainer(DockerImageName dockerImageName) {

        super(dockerImageName);
        this.databaseName = "test";
        this.username = "test";
        this.password = "test";
        this.waitStrategy = (new LogMessageWaitStrategy()).withRegEx(".*database system is ready to accept connections.*")
                .withTimes(1)
                .withStartupTimeout(Duration.of(60L, ChronoUnit.SECONDS));
        this.addExposedPort(POSTGRESQL_PORT);
        configure();
    }



    protected @NotNull Set<Integer> getLivenessCheckPorts() {

        return Collections.singleton(this.getMappedPort(POSTGRESQL_PORT));
    }


    protected void configure() {

        this.addEnv("POSTGRESQL_DATABASE", this.databaseName);
        this.addEnv("POSTGRESQL_USERNAME", this.username);
        this.addEnv("POSTGRESQL_PASSWORD", this.password);
    }


    public String getDriverClassName() {

        return "org.postgresql.Driver";
    }


    public String getJdbcUrl() {

        String additionalUrlParams = this.constructUrlParameters("?", "&");
        return "jdbc:postgresql://" + this.getContainerIpAddress() + ":" + this.getMappedPort(POSTGRESQL_PORT) + "/" + this.databaseName + additionalUrlParams;
    }


    public String getDatabaseName() {

        return this.databaseName;
    }


    public String getUsername() {

        return this.username;
    }


    public String getPassword() {

        return this.password;
    }


    public String getTestQueryString() {

        return "SELECT 1";
    }


    public KneconSpringPostgreSQLTestContainer withDatabaseName(String databaseName) {

        this.databaseName = databaseName;
        return this.self();
    }


    public KneconSpringPostgreSQLTestContainer withUsername(String username) {

        this.username = username;
        return this.self();
    }


    public KneconSpringPostgreSQLTestContainer withPassword(String password) {

        this.password = password;
        return this.self();
    }


    protected void waitUntilContainerStarted() {

        this.getWaitStrategy().waitUntilReady(this);
    }

}
