package org.apache.torque.testcontainer.junit5.extension;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

import static org.junit.jupiter.api.extension.ConditionEvaluationResult.enabled;

import java.io.File;

import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
import org.junit.jupiter.api.extension.ExecutionCondition;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;

/**
 * Testcontainer configuration for database Postgres
 * 
 * Requires some configuration data found for example in {@link DockerPostGresCallback}.
 * 
 * @author gk
 *
 */
@Testcontainers
public class DockerCallbackPostgreSQLExtension extends DockerDatabaseAbstractExtension
        implements BeforeAllCallback, BeforeTestExecutionCallback, ExecutionCondition
{

    private static org.slf4j.Logger log = LoggerFactory.getLogger( DockerCallbackPostgreSQLExtension.class );

    private static int SERVICE_PORT = 5432;

    private static final ConditionEvaluationResult ENABLED_BY_DEFAULT = enabled(
            "DockerCallbackExtension is enabled by default - checking internal state only" );

    /**
     * podman issue: https://github.com/testcontainers/testcontainers-java/issues/5998
     */
    @Container
    public static GenericContainer DATABASE_CONTAINER = new GenericContainer<>(
            new ImageFromDockerfile().withDockerfile(new File(DOCKERFILE).toPath())).withExposedPorts(SERVICE_PORT) 
                    .withEnv("POSTGRES_DB", DATABASE_NAME).withEnv("POSTGRES_USER", "torque")
                    .withEnv("POSTGRES_PASSWORD", "torque").withLogConsumer(new Slf4jLogConsumer(log));

    public DockerCallbackPostgreSQLExtension()
    {
        log.warn( "DATABASE_CONTAINER: {}", DATABASE_CONTAINER );
        if (DATABASE_CONTAINER == null)
        {
            DockerImageName fqdImage = DockerImageName.parse( "postgres:15.2" );
            log.warn( "hard coded init container not from Testcontainers Container annotation {}" );
            DATABASE_CONTAINER = new GenericContainer<>( fqdImage );
            DATABASE_CONTAINER.withExposedPorts( SERVICE_PORT ).withEnv( "POSTGRES_DB", DATABASE_NAME )
                    .withEnv( "POSTGRES_USER", "torque" ).withEnv( "POSTGRES_PASSWORD", "torque" )
                    .withLogConsumer( new Slf4jLogConsumer( log ) );
        }
        setDbContainer( DATABASE_CONTAINER );
        log.warn( "DATABASE_CONTAINER: {}", DATABASE_CONTAINER );
        setServicePort( SERVICE_PORT );
    }

    @Override
    public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context)
    {
        String actual = System.getProperty( "torque.callback" );
        if (actual == null)
        {
            actual = System.getenv( "torque.callback" );
        }
        if (actual != null && actual.matches( "docker" ))
        {
        }
        return ENABLED_BY_DEFAULT;
    }

    @Override
    public void beforeAll(ExtensionContext context) throws Exception
    {
        // log.info("starting call context "+ context);
        Class<?> clazz = context.getRequiredTestClass();
        log.warn( "found and get annotation : {}", (Object[]) context.getRequiredTestClass().getAnnotations() );
        DockerPostGresCallback dockerCallback = clazz.getAnnotation( DockerPostGresCallback.class );
        if (dockerCallback != null)
        {
            log.warn( "using annotation: {}", dockerCallback );
            setSkipConfigurationCheck( dockerCallback.skipConfigurationCheck() );
            setCustomUrlKey( dockerCallback.customUrlKey() );
            setTargetConfigName( dockerCallback.targetConfigName() );
            setTargetFileName( dockerCallback.targetFileName() );
            setAdapterProfileFallback( dockerCallback.adapterProfileFallback() );
        } else
        {
            super.beforeAll( context );
        }
        try
        {
            dbInit( context );
        } catch (Exception e)
        {
            final String logs = DATABASE_CONTAINER.getLogs();
            log.info( "fetched container logs: {} ", logs );
            throw e;
        }
        String jdbcConnectionString = generateJdbcUrl( "" );
        context.getStore( Namespace.GLOBAL ).put( "jdbcConnectionString", jdbcConnectionString );
        context.getStore( Namespace.GLOBAL ).put( "container", DATABASE_CONTAINER );
        context.getStore( Namespace.GLOBAL ).put( "annotatedClass", dockerCallback );

        torqueInit( context );
    }

    @Override
    public void beforeTestExecution(ExtensionContext context) throws Exception
    {
        // log.info("starting call test context "+ context);
    }

}
