package src.fr.test;

import java.util.Set;
import java.util.HashSet;


import static org.junit.Assert.*;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;

import src.fr.impl.*;
import src.fr.impl.Parts.*;
import src.fr.api.*;

public class test_V1 {
    
    CategoryImpl engine = new CategoryImpl("Engine");
    CategoryImpl transmission = new CategoryImpl("Transmission");
    CategoryImpl exterior = new CategoryImpl("Exterior");
    CategoryImpl interior = new CategoryImpl("Interior");

    //PartType
    PartType EG100= new PartTypeImpl("EG100",Engine.class, engine);
    PartType EG133= new PartTypeImpl("EG133",Engine.class, engine);
    PartType EG210= new PartTypeImpl("EG210",Engine.class, engine);
    PartType ED110= new PartTypeImpl("ED110",Engine.class, engine);
    PartType ED180= new PartTypeImpl("ED180",Engine.class, engine);
    PartType EH120= new PartTypeImpl("EH120",Engine.class, engine);

    PartType TM5= new PartTypeImpl("TM5", Transmission.class ,transmission);
    PartType TM6= new PartTypeImpl("TM6", Transmission.class ,transmission);
    PartType TA5= new PartTypeImpl("TA5", Transmission.class ,transmission);
    PartType TS6= new PartTypeImpl("TS6", Transmission.class ,transmission);
    PartType TSF7= new PartTypeImpl("TSF7", Transmission.class ,transmission);
    PartType TC120= new PartTypeImpl("TC120", Transmission.class ,transmission);

    PartType XC= new PartTypeImpl("XC", Exterior.class,exterior);
    PartType XM= new PartTypeImpl("XM", Exterior.class,exterior);
    PartType XS= new PartTypeImpl("XS", Exterior.class,exterior);

    PartType IN= new PartTypeImpl("IN", Interior.class ,interior);
    PartType IH= new PartTypeImpl("IH", Interior.class ,interior);
    PartType IS= new PartTypeImpl("IS", Interior.class ,interior);

    CompatibilityManager cm;


    @BeforeEach
    public void init(){

        cm = new CompatibilityManagerImpl();

        Set<PartType> EH120Requirement = new HashSet<PartType>();
        EH120Requirement.add(TC120);

        Set<PartType> TA5Incompatibilities = new HashSet<PartType>();
        TA5Incompatibilities.add(EG100);

        Set<PartType> TSF7Incompatibilities = new HashSet<PartType>();
        TSF7Incompatibilities.add(EG100);
        TSF7Incompatibilities.add(EG133);
        TSF7Incompatibilities.add(ED110);

        Set<PartType> TC120Requirement = new HashSet<PartType>();
        TC120Requirement.add(EH120);

        Set<PartType> XCIncompatibilities = new HashSet<PartType>();
        XCIncompatibilities.add(EG210);

        Set<PartType> XMIncompatibilities = new HashSet<PartType>();
        XMIncompatibilities.add(EG100);

        Set<PartType> XSIncompatibilities = new HashSet<PartType>();
        XSIncompatibilities.add(EG100);
        Set<PartType> XSRequirement = new HashSet<PartType>();
        XSRequirement.add(IS);

        Set<PartType> ISIncompatibilities = new HashSet<PartType>();
        ISIncompatibilities.add(EG100);
        ISIncompatibilities.add(TM5);
        Set<PartType> ISRequirement = new HashSet<PartType>();
        ISRequirement.add(XS);

        cm.addRequirements(EH120, EH120Requirement);
        cm.addIncompatibilities(TA5, TA5Incompatibilities);
        cm.addIncompatibilities(TSF7, TSF7Incompatibilities);
        cm.addRequirements(TC120, TC120Requirement);
        cm.addIncompatibilities(XC, XCIncompatibilities);
        cm.addIncompatibilities(XM, XMIncompatibilities);
        cm.addIncompatibilities(XS, XSIncompatibilities);
        cm.addRequirements(XS, XSRequirement);
        cm.addIncompatibilities(IS, ISIncompatibilities);
        cm.addRequirements(IS, ISRequirement);
    }

    //compatibilitiesManager

    @Test
    public void test_Incompatibilities_Simple_1(){
        assertTrue(cm.getIncompatibilities(TA5).contains(EG100));
    }

    @Test
    public void test_multiple_Incompatibilities_Simple_2(){
        assertTrue(
            cm.getIncompatibilities(TSF7).contains(EG100)&&
            cm.getIncompatibilities(TSF7).contains(EG133)&&
            cm.getIncompatibilities(TSF7).contains(ED110)
            );
    }

    @Test
    public void test_Requirements_3(){
        assertTrue(cm.getRequirements(EH120).contains(TC120));
    }



    /*
     * A <-> B
     * if A -> B then B -> A
     */
    @Test
    public void test_Incompatibilities_Complex_4(){
        System.out.println("size EG100 incompatibilities : "+cm.getIncompatibilities(EG100).size());
        assertTrue(cm.getIncompatibilities(EG100).contains(IS));
        assertTrue(cm.getIncompatibilities(EG100).contains(XS));
    }

    /*
     * if A require B
     * then A is incompatible with all incompatible of B
     */
    @Test
    public void test_Require_Incompatibilities_Complex_5(){
        assertTrue(cm.getIncompatibilities(XS).contains(EG100));
        System.out.println("size XS incompatibilities : " + cm.getIncompatibilities(XS).size());
        assertTrue(cm.getIncompatibilities(XS).contains(TM5));
    }


    /*
     *    Require   Require     Require
     * if A -> B && B -> C then A -> C
     */
    @Test
    public void test_Incompatibilities_Complex_7(){
        cm.addRequirements(TC120, Set.of(XC));
        assertTrue(cm.getRequirements(TC120).contains(XC));
        assertTrue(cm.getRequirements(EH120).contains(XC));
        cm.removeRequirement(TC120, XC);
    }

    @Test
    public void test_Empty_Requirements_5(){
        assertTrue(cm.getRequirements(ED180).isEmpty());
    }
    
    @Test
    public void test_Remove_and_restore_Incompatibilities_6(){
        assertTrue(cm.getIncompatibilities(XM).contains(EG100));
        cm.removeIncompatibility(XM, EG100);
        assertFalse(cm.getIncompatibilities(XM).contains(EG100));
        Set<PartType> setEG100 = new HashSet<PartType>();
        setEG100.add(EG100);
        cm.addIncompatibilities(XM, setEG100);
        assertTrue(cm.getIncompatibilities(XM).contains(EG100));
    }

    @Test
    public void test_Remove_Empty_7(){
        assertTrue(cm.getIncompatibilities(EH120).isEmpty());
        cm.removeIncompatibility(EH120, EG100);
        assertTrue(cm.getIncompatibilities(EH120).isEmpty());    }

    @Test
    public void test_Remove_and_restore_Requirements_8(){
        assertTrue(cm.getRequirements(EH120).contains(TC120));
        cm.removeRequirement(EH120, TC120);
        assertFalse(cm.getRequirements(EH120).contains(TC120));
        Set<PartType> setTC120 = new HashSet<PartType>();
        setTC120.add(TC120);
        cm.addRequirements(EH120, setTC120);
        assertTrue(cm.getRequirements(EH120).contains(TC120));
    }

    @Test
    public void test_remove_incompatibilities_but_no_removable(){
        assertTrue(cm.getIncompatibilities(EG100).contains(IS));
        cm.removeIncompatibility(EG100, IS);
        assertTrue(cm.getIncompatibilities(EG100).contains(IS));
    }

    @Test
    public void test_Add_and_restore_Incompatibilities_9(){
        assertTrue(cm.getIncompatibilities(TSF7).contains(EG100));
        assertTrue(cm.getIncompatibilities(TSF7).contains(EG133));
        assertTrue(cm.getIncompatibilities(TSF7).contains(ED110));
        cm.removeIncompatibility(TSF7, EG100);
        assertFalse(cm.getIncompatibilities(TSF7).contains(EG100));
        assertTrue(cm.getIncompatibilities(TSF7).contains(EG133));
        assertTrue(cm.getIncompatibilities(TSF7).contains(ED110));
        Set<PartType> setEG100 = new HashSet<PartType>();
        setEG100.add(EG100);
        cm.addIncompatibilities(TSF7, setEG100);
        assertTrue(cm.getIncompatibilities(TSF7).contains(EG100));
        assertTrue(cm.getIncompatibilities(TSF7).contains(EG133));
        assertTrue(cm.getIncompatibilities(TSF7).contains(ED110));
    }

    //Configuration

    @Test
    public void test_isComplete(){
        ConfigurationImpl config1 = new ConfigurationImpl(cm);
        config1.selectPart(EG210);
        config1.selectPart(TM5);
        config1.selectPart(XS);
        config1.selectPart(IS);

        assertTrue(config1.isComplete());
    }

    @Test
    public void test_isNotComplete(){
        ConfigurationImpl config1 = new ConfigurationImpl(cm);
        config1.selectPart(EG210);
        config1.selectPart(TM5);
        config1.selectPart(XS);

        assertFalse(config1.isComplete());
    }

    @Test
    public void test_isNotComplete_empty_cm(){
        CompatibilityManager cm2 = new CompatibilityManagerImpl();
        ConfigurationImpl config1 = new ConfigurationImpl(cm2);
        config1.selectPart(EG210);
        config1.selectPart(TM5);
        config1.selectPart(XS);

        assertFalse(config1.isComplete());
    }

    @Test
    public void test_isValide_empty_cm(){
        CompatibilityManager cm2 = new CompatibilityManagerImpl();
        ConfigurationImpl config1 = new ConfigurationImpl(cm2);
        config1.selectPart(EG210);
        config1.selectPart(TM5);
        config1.selectPart(XS);
        config1.selectPart(IS);

        assertTrue(config1.isValid());
    }

    @Test
    public void test_isValide1(){
        ConfigurationImpl config1 = new ConfigurationImpl(cm);
        config1.selectPart(EG210);
        config1.selectPart(TSF7);
        config1.selectPart(XS);
        config1.selectPart(IS);

        assertTrue(config1.isValid());
    }


    @Test
    public void test_isValide2(){
        ConfigurationImpl config1 = new ConfigurationImpl(cm);
        config1.selectPart(EG210);
        config1.selectPart(TSF7);
        config1.selectPart(XS);
        config1.selectPart(IS);
        config1.selectPart(TS6);

        assertTrue(config1.isValid());
    }

    @Test
    public void test_isNotValide1(){
        ConfigurationImpl config1 = new ConfigurationImpl(cm);
        config1.selectPart(EG100);
        config1.selectPart(TSF7);
        config1.selectPart(XS);
        config1.selectPart(IS);

        assertFalse(config1.isValid());
    }

    @Test
    public void test_isNotValide2(){
        ConfigurationImpl config1 = new ConfigurationImpl(cm);
        config1.selectPart(EG210);
        config1.selectPart(TSF7);
        config1.selectPart(XS);
        config1.selectPart(XS);

        assertFalse(config1.isValid());
    }

    @Test
    public void test_isValide_but_not_complete(){
        ConfigurationImpl config1 = new ConfigurationImpl(cm);
        config1.selectPart(EG210);
        config1.selectPart(TSF7);

        assertTrue(config1.isValid());
    }

}
