package it.unibz.inf.ontop.iq.optimizer;

import it.unibz.inf.ontop.dbschema.*;
import it.unibz.inf.ontop.iq.IQ;
import it.unibz.inf.ontop.iq.exception.EmptyQueryException;
import it.unibz.inf.ontop.iq.node.ConstructionNode;
import it.unibz.inf.ontop.iq.node.ExtensionalDataNode;
import it.unibz.inf.ontop.iq.node.FilterNode;
import it.unibz.inf.ontop.model.atom.AtomPredicate;
import it.unibz.inf.ontop.model.atom.DistinctVariableOnlyDataAtom;
import it.unibz.inf.ontop.model.atom.RelationPredicate;
import it.unibz.inf.ontop.model.term.Constant;
import it.unibz.inf.ontop.model.term.Variable;
import org.junit.Test;

import java.sql.Types;

import static it.unibz.inf.ontop.OptimizationTestingTools.*;
import static org.junit.Assert.assertTrue;

public class NRAJoinOptimizerTest {
////    private static final DBMetadata DB_METADATA;
//    private static final RelationPredicate TABLE1_PREDICATE;
//    private static final RelationPredicate TABLE2_PREDICATE;
//    private static final RelationPredicate TABLE3_PREDICATE;
//    private static final RelationPredicate NESTED_VIEW1;
//    private static final RelationPredicate NESTED_VIEW2;
//    private static final RelationPredicate NESTED_VIEW3;
//    private static final RelationPredicate NESTED_VIEW4;
//
//    private final static AtomPredicate ANS1_PREDICATE = ATOM_FACTORY.getRDFAnswerPredicate(1);
//    private final static AtomPredicate ANS2_PREDICATE = ATOM_FACTORY.getRDFAnswerPredicate(2);
//    private final static AtomPredicate ANS4_PREDICATE = ATOM_FACTORY.getRDFAnswerPredicate(4);
//
//    private final static Variable A = TERM_FACTORY.getVariable("A");
//    private final static Variable A1 = TERM_FACTORY.getVariable("A1");
//    private final static Variable A2 = TERM_FACTORY.getVariable("A2");
//    private final static Variable B = TERM_FACTORY.getVariable("B");
//    private final static Variable B1 = TERM_FACTORY.getVariable("B1");
//    private final static Variable B2 = TERM_FACTORY.getVariable("B2");
//    private final static Variable C = TERM_FACTORY.getVariable("C");
//    private final static Variable C1 = TERM_FACTORY.getVariable("C1");
//    private final static Variable C2 = TERM_FACTORY.getVariable("C2");
//    private final static Variable C3 = TERM_FACTORY.getVariable("C3");
//    private final static Variable C4 = TERM_FACTORY.getVariable("C4");
//    private final static Variable D = TERM_FACTORY.getVariable("D");
//    private final static Variable D1 = TERM_FACTORY.getVariable("D1");
//    private final static Variable D2 = TERM_FACTORY.getVariable("D2");
//    private final static Variable E = TERM_FACTORY.getVariable("E");
//    private final static Variable F0 = TERM_FACTORY.getVariable("f0");
//    private final static Variable F1 = TERM_FACTORY.getVariable("f1");
//    private final static Variable F2 = TERM_FACTORY.getVariable("f2");
//    private final static Variable F3 = TERM_FACTORY.getVariable("f3");
//    private final static Variable F4 = TERM_FACTORY.getVariable("f4");
//    private final static Variable F5 = TERM_FACTORY.getVariable("f5");
//    private final static Variable G = TERM_FACTORY.getVariable("G");
//    private final static Variable N = TERM_FACTORY.getVariable("N");
//    private final static Variable X = TERM_FACTORY.getVariable("X");
//    private final static Variable Y = TERM_FACTORY.getVariable("Y");
//    private final static Variable Z = TERM_FACTORY.getVariable("Z");
//
//    private static final Constant ONE = TERM_FACTORY.getConstantLiteral("1");
//    private static final Constant TWO = TERM_FACTORY.getConstantLiteral("2");
//
//    static {
//        BasicDBMetadata dbMetadata = createDummyMetadata();
//        QuotedIDFactory idFactory = dbMetadata.getQuotedIDFactory();
//
//        // has nestedView1 as child, and no parent
//        DatabaseRelationDefinition table1Def = dbMetadata.createDatabaseRelation(idFactory.createRelationID(null, "table1"));
//        Attribute col1T1 = table1Def.addAttribute(idFactory.createAttributeID("pk"), Types.INTEGER, null, false);
//        table1Def.addAttribute(idFactory.createAttributeID("col1"), Types.INTEGER, null, true);
//        table1Def.addAttribute(idFactory.createAttributeID("arr1"), Types.ARRAY, null, true);
//        table1Def.addUniqueConstraint(UniqueConstraint.primaryKeyOf(col1T1));
//        TABLE1_PREDICATE = table1Def.getAtomPredicate();
//
//        DatabaseRelationDefinition table2Def = dbMetadata.createDatabaseRelation(idFactory.createRelationID(null, "table2"));
//        Attribute col1T2 = table2Def.addAttribute(idFactory.createAttributeID("pk"), Types.INTEGER, null, false);
//        table2Def.addAttribute(idFactory.createAttributeID("col1"), Types.INTEGER, null, true);
//        table2Def.addUniqueConstraint(UniqueConstraint.primaryKeyOf(col1T2));
//        TABLE2_PREDICATE = table2Def.getAtomPredicate();
//
//
//        DatabaseRelationDefinition table3Def = dbMetadata.createDatabaseRelation(idFactory.createRelationID(null, "table3"));
//        Attribute col1T3 = table3Def.addAttribute(idFactory.createAttributeID("pk"), Types.INTEGER, null, false);
//        table3Def.addAttribute(idFactory.createAttributeID("arr1"), Types.ARRAY, null, true);
//        table3Def.addAttribute(idFactory.createAttributeID("arr2"), Types.ARRAY, null, true);
//        table3Def.addUniqueConstraint(UniqueConstraint.primaryKeyOf(col1T3));
//        TABLE3_PREDICATE = table3Def.getAtomPredicate();
//
//        // has table1 as parent
//        NestedView nestedView1 = dbMetadata.createNestedView(
//                idFactory.createRelationID(null, "nestedView1"),
//                table1Def,
//                FLATTEN_NODE_PRED_AR3.getRelationDefinition(),
//                2
//        );
//        Attribute col1N1 = nestedView1.addAttribute(idFactory.createAttributeID("pk"), Types.INTEGER, null, false);
//        nestedView1.addAttribute(idFactory.createAttributeID("col1"), Types.INTEGER, null, true);
//        nestedView1.addAttribute(idFactory.createAttributeID("arr1"), Types.ARRAY, null, false);
//        nestedView1.addUniqueConstraint(UniqueConstraint.primaryKeyOf(col1N1));
//        NESTED_VIEW1 = nestedView1.getAtomPredicate();
//
//        // has nestedView1 as parent
//        NestedView nestedView2 = dbMetadata.createNestedView(
//                idFactory.createRelationID(null, "nestedView2"),
//                nestedView1,
//                FLATTEN_NODE_PRED_AR3.getRelationDefinition(),
//                2
//        );
//        Attribute col1N2 = nestedView2.addAttribute(idFactory.createAttributeID("pk"), Types.INTEGER, null, false);
//        nestedView2.addAttribute(idFactory.createAttributeID("col1"), Types.INTEGER, null, true);
//        nestedView2.addAttribute(idFactory.createAttributeID("col2"), Types.INTEGER, null, false);
//        nestedView2.addUniqueConstraint(UniqueConstraint.primaryKeyOf(col1N2));
//        NESTED_VIEW2 = nestedView2.getAtomPredicate();
//
//        // has table3 as parent
//        NestedView nestedView3 = dbMetadata.createNestedView(
//                idFactory.createRelationID(null, "nestedView3"),
//                table3Def,
//                FLATTEN_NODE_PRED_AR3.getRelationDefinition(),
//                2
//        );
//
//        Attribute col1N3 = nestedView3.addAttribute(idFactory.createAttributeID("pk"), Types.INTEGER, null, false);
//        nestedView3.addAttribute(idFactory.createAttributeID("col1"), Types.INTEGER, null, true);
//        nestedView3.addAttribute(idFactory.createAttributeID("col2"), Types.INTEGER, null, false);
//        nestedView3.addUniqueConstraint(UniqueConstraint.primaryKeyOf(col1N3));
//        NESTED_VIEW3 = nestedView3.getAtomPredicate();
//
//        // has table3 as parent
//        NestedView nestedView4 = dbMetadata.createNestedView(
//                idFactory.createRelationID(null, "nestedView4"),
//                table1Def,
//                FLATTEN_NODE_PRED_AR4.getRelationDefinition(),
//                3
//        );
//
//        Attribute col1N4 = nestedView4.addAttribute(idFactory.createAttributeID("pk"), Types.INTEGER, null, false);
//        nestedView4.addAttribute(idFactory.createAttributeID("col1"), Types.INTEGER, null, true);
//        nestedView4.addAttribute(idFactory.createAttributeID("col2"), Types.INTEGER, null, false);
//        nestedView4.addUniqueConstraint(UniqueConstraint.primaryKeyOf(col1N3));
//        NESTED_VIEW4 = nestedView3.getAtomPredicate();
//
//        dbMetadata.freeze();
//        DB_METADATA = dbMetadata;
//    }
//
//
//
//    @Test
//    public void testFlattenLift1() throws EmptyQueryException {
//        IntermediateQueryBuilder queryBuilder = createQueryBuilder(DB_METADATA);
//        DistinctVariableOnlyDataAtom projectionAtom = ATOM_FACTORY.getDistinctVariableOnlyDataAtom(ANS1_PREDICATE, X);
//        ConstructionNode rootNode = IQ_FACTORY.createConstructionNode(projectionAtom.getVariables());
//        queryBuilder.init(projectionAtom, rootNode);
//
//        FilterNode filterNode = IQ_FACTORY.createFilterNode(
//                TERM_FACTORY.getImmutableExpression(EQ, B, ONE)
//        );
//        queryBuilder.addChild(rootNode, filterNode);
//
//        ExtensionalDataNode dataNode = IQ_FACTORY.createExtensionalDataNode(
//                ATOM_FACTORY.getDataAtom(NESTED_VIEW1, X, B, C));
//        queryBuilder.addChild(filterNode, dataNode);
//
//
//        IntermediateQuery query = queryBuilder.build();
//
//        IntermediateQueryBuilder expectedQueryBuilder = createQueryBuilder(DB_METADATA);
//        expectedQueryBuilder.init(projectionAtom, rootNode);
//        StrictFlattenNode flattenNode = IQ_FACTORY.createStrictFlattenNode(F0, 0,
//                ATOM_FACTORY.getDataAtom(FLATTEN_NODE_PRED_AR3, X, B, C));
//        expectedQueryBuilder.addChild(rootNode,filterNode);
//        expectedQueryBuilder.addChild(flattenNode, filterNode);
//
//        expectedQueryBuilder.addChild(filterNode, IQ_FACTORY.createExtensionalDataNode(
//                ATOM_FACTORY.getDataAtom(TABLE1_PREDICATE, F1, F2, F0)));
//
//        IntermediateQuery expectedQuery = expectedQueryBuilder.build();
//
//        optimizeAndCompare(query, expectedQuery);
//    }
//
//    private static void optimizeAndCompare(IntermediateQuery query, IntermediateQuery expectedQuery) throws EmptyQueryException {
//        System.out.println("\nBefore optimization: \n" +  query);
//        System.out.println("\nExpected: \n" +  expectedQuery);
//
//        IQ optimizedIQ = NRA_JOIN_LIKE_OPTIMIZER.optimize(IQ_CONVERTER.convert(query), query.getExecutorRegistry());
//        IntermediateQuery optimizedQuery = IQ_CONVERTER.convert(
//                optimizedIQ,
//                query.getExecutorRegistry()
//        );
//        System.out.println("\nAfter optimization: \n" +  optimizedQuery);
//
//        assertTrue(IQSyntacticEquivalenceChecker.areEquivalent(optimizedQuery, expectedQuery));
//    }
}
