/*
 * Copyright © 2012-2024 by Data Virtuality GmbH
 */
package org.teiid.query.resolver.command;

import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.teiid.api.exception.query.QueryResolverException;
import org.teiid.query.metadata.*;
import org.teiid.query.parser.QueryParser;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.unittest.RealMetadataFactory;
import org.teiid.util.TestingCreateTableWrapper;

import java.util.stream.Stream;

/**
 * This test is focused on issues raised in DVCORE-8550
 * @author Arseniy Kaleshnyk
 * @date 2024.12.09
 */
public class TestTempTableResolver {
    public static final String DUPLICATE_TEMPLATE = "The %s with such a name already exists. Please provide a different table name: %s";
    public static final String FULL_DUPLICATE_TEMPLATE = "TEIID301183 " + DUPLICATE_TEMPLATE + ".";
    private static final QueryMetadataInterface bqtMetadata =  RealMetadataFactory.exampleBQT();
    private static final String CREATE = "CREATE TABLE %s.%s (column1 INTEGER)";

    private static Stream<Arguments> bqtTableAndViews() {
        // BQT1
        return Stream.of(
                Arguments.of("BQT1", "SmallB", "table"),
                Arguments.of("bqt1", "MediumA", "table"),
                Arguments.of("vqt", "SmallB", "view")
        );
    }

    @ParameterizedTest()
    @Tag("DVCORE-8550")
    @MethodSource("bqtTableAndViews")
    public void testResolveCommandCreateForDuplicates2(
            String schemaName, String tableName, String resourceType) throws Exception {
        String createQuery = String.format(CREATE, schemaName, tableName);
        TempMetadataAdapter tempMetadataAdapter = new TempMetadataAdapter(bqtMetadata, new TempMetadataStore());
        Command command1 = QueryParser.getQueryParser().parseCommand(createQuery);
        TempTableResolver resolver = new TempTableResolver();
        resolver.resolveCommand(new TestingCreateTableWrapper(command1),
                tempMetadataAdapter, null, true);
    }

    private static Stream<Arguments> bqtQueries() {
        // BQT1
        return Stream.of(
                Arguments.of( // matches int test method 'testSameDwhTable'
                        "CREATE TABLE BQT1.%s (column1 INTEGER)",
                        "CREATE TABLE BQT1.%s (column1 INTEGER)"),
                Arguments.of( // matches int test method 'testAlteredDwhTable'
                        "CREATE TABLE BQT1.%s (column1 INTEGER)",
                        "CREATE TABLE BQT1.%s (column2 STRING)")
        );
    }

    /**
     * Checks how TempTableResolver reacts on command "create table" with duplicate name
     * @see DVCORE-8550
     */
    @ParameterizedTest()
    @Tag("DVCORE-8550")
    @MethodSource("bqtQueries")
    public void testResolveCommandCreateForDuplicates(String sql1, String sql2) throws Exception {
        String tableName = "test_table_dvcore8550";
        TempMetadataAdapter tempMetadataAdapter = new TempMetadataAdapter(bqtMetadata, new TempMetadataStore());
        Command command1 = QueryParser.getQueryParser().parseCommand(String.format(sql1, tableName));
        Command command2 = QueryParser.getQueryParser().parseCommand(String.format(sql2, tableName));
        TempTableResolver resolver = new TempTableResolver();

        resolver.resolveCommand(new TestingCreateTableWrapper(command1),
                tempMetadataAdapter, null, true);
        resolver.resolveCommand(new TestingCreateTableWrapper(command2),
                tempMetadataAdapter, null, true);
    }

    private void verifyException(String name, String resourceType, Exception e) {
        Assertions.assertInstanceOf(QueryResolverException.class, e, "Expected QueryResolverException");
        Assertions.assertTrue(e.getMessage().contains(name), "Exception message should contain " + resourceType + " name : " + e.getMessage());
        Assertions.assertTrue(
                e.getMessage().contains(
                        String.format(DUPLICATE_TEMPLATE, resourceType, "")),
                "Exception message should inform about existence of " + resourceType + " : " + e.getMessage());
        Assertions.assertTrue(
                e.getMessage().contains(
                        String.format(DUPLICATE_TEMPLATE, resourceType, name)),
                "Exception message altered : " + e.getMessage());
        Assertions.assertEquals(
                String.format(FULL_DUPLICATE_TEMPLATE, resourceType, name),
                e.getMessage(),
                "Exception message altered : " + e.getMessage());
    }

}
