/*
 * Copyright © 2025 by Data Virtuality GmbH
 */

package org.teiid.query.util;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.optimizer.TestAggregatePushdown;
import org.teiid.query.optimizer.TestOptimizer;
import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
import org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder;
import org.teiid.query.parser.QueryParser;
import org.teiid.query.processor.FakeDataManager;
import org.teiid.query.processor.ProcessorPlan;
import org.teiid.query.processor.TestProcessor;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.Query;
import org.teiid.query.unittest.RealMetadataFactory;

import java.util.stream.Stream;

/**
 * @author Arseniy Kaleshnyk
 * @date 2025.06.20
 */
public class TestCommandContext {

    private static QueryMetadataInterface CACHED_X1 = RealMetadataFactory.example1Cached();

    public static Stream<Arguments> contextArguments() {
        return Stream.of(
                Arguments.of("empty", new CommandContext(), false),
                Arguments.of("TestProcessor", TestProcessor.createCommandContext(), false)
        );
    }

    public static Stream<Arguments> capsArguments() {
        return Stream.of(
                Arguments.of("default", new DefaultCapabilitiesFinder()),
                Arguments.of("TestOptimizer.genericFinder", TestOptimizer.getGenericFinder()),
                Arguments.of("TestOptimizer.typical", TestOptimizer.getGenericFinder(false)),
                Arguments.of("TestOptimizer.typicalWithJoins", TestOptimizer.getGenericFinder(true)),
                Arguments.of("TestAggregatePushdown.typicalCapabilities",
                        new DefaultCapabilitiesFinder(TestAggregatePushdown.getAggregateCapabilities()))
        );
    }

    public static Stream<Arguments> queryArgumentsForScoped() {
        return Stream.of(
                Arguments.of("TestProcessor.test1",
                        "SELECT pm1.g1.e1, e2, pm1.g1.e3 as a, e4 as b FROM pm1.g1"),
                Arguments.of("TestProcessor.testSubqueryINClauses",
                        "SELECT e1 FROM pm1.g1 WHERE e2 IN (SELECT e2 FROM pm2.g1) AND e1 IN (SELECT e1 FROM pm2.g1)"),
                Arguments.of("TestProcessor.testNonJoinCriteriaInFromNestedInVirtual",
                        "SELECT a.e1, b.e1, b.e2 FROM pm1.g1 a LEFT OUTER JOIN (SELECT c.e1, d.e2 FROM pm2.g1 c JOIN pm2.g1 d ON c.e1=d.e1 AND d.e2 >= 0) b ON a.e1=b.e1 AND b.e2 = 0")
        );
    }

    private static Stream<Object[]> multi() {
        return queryArgumentsForScoped()
                .flatMap(queryArg -> contextArguments()
                        .flatMap(ccArg -> capsArguments()
                                .map(capsArg -> new Object[]{
                                        makeTitle(queryArg.get()[0], ccArg.get()[0], capsArg.get()[0]),
                                        queryArg.get()[1], ccArg.get()[1], capsArg.get()[1]})
                        )
                );
    }

    private static String makeTitle(Object arg1, Object arg2, Object arg3) {
        return arg1 + "-CC[" + arg2 + "]-Caps[" + arg3+"]";
    }

    @ParameterizedTest(name = "{0}")
    @Tag("DVCORE-8890")
    @DisplayName("check isScoped of typical CommandContext")
    @MethodSource("contextArguments")
    public void testScopedOfTypicalCommandContext(String title, CommandContext commandContext, boolean expectedScoped) {
        Assertions.assertEquals(expectedScoped, commandContext.isScoped(new Query() {
            // dummy command for test
            public String toString() {
                return "theCommand";
            }
        }));
    }

    @ParameterizedTest(name = "{0}")
    @Tag("DVCORE-8890")
    @DisplayName("check isScoped on parameters: query-CommandContext-Caps")
    @MethodSource({"multi", })
    public void testScopedOnQueries(String title, String query, CommandContext ctx, CapabilitiesFinder capsFinder) throws Exception {
        Command command = QueryParser.getQueryParser().parseCommand(query);
        ProcessorPlan plan = TestProcessor.helpGetPlan(command, CACHED_X1, capsFinder, ctx);
        ctx.isScoped(command);
//        TestProcessor.doProcess(plan, new FakeDataManager(), null, ctx);
//        ctx.isScoped(command);
    }

}
