package perceptron;

import com.naaturel.ANN.domain.abstraction.AlgorithmStep;
import com.naaturel.ANN.domain.abstraction.Model;
import com.naaturel.ANN.domain.model.helpers.ModelCreator;
import com.naaturel.ANN.infrastructure.dataset.DataSet;
import com.naaturel.ANN.infrastructure.dataset.DatasetExtractor;
import com.naaturel.ANN.domain.model.neuron.*;
import com.naaturel.ANN.domain.model.training.TrainingPipeline;
import com.naaturel.ANN.implementation.simplePerceptron.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;


public class SimplePerceptronTest {

    private DataSet dataset;
    private SimpleTrainingContext context;
    private Model model;

    private TrainingPipeline pipeline;

    @BeforeEach
    public void init(){
        dataset = new DatasetExtractor()
                .extract("C:/Users/Laurent/Desktop/ANN-framework/src/main/resources/assets/and.csv", 1);

        List<Synapse> syns = new ArrayList<>();
        syns.add(new Synapse(new Input(0), new Weight(0)));
        syns.add(new Synapse(new Input(0), new Weight(0)));

        model = ModelCreator.createModel(new int[]{1}, 2, new Heaviside());

        context = new SimpleTrainingContext(model, dataset);

        List<AlgorithmStep> steps = List.of(
                new SimplePredictionStep(context),
                new SimpleDeltaStep(context),
                new SimpleLossStrategy(context),
                new SimpleErrorRegistrationStep(context),
                new SimpleCorrectionStep(context)
        );

        pipeline = new TrainingPipeline(steps);
        pipeline.stopCondition(ctx -> ctx.globalLoss == 0.0F || ctx.epoch > 100);
        pipeline.beforeEpoch(ctx -> ctx.globalLoss = 0);
    }

    @Test
    public void test_the_whole_algorithm(){

        List<Float> expectedGlobalLosses = List.of(
                2.0F,
                3.0F,
                3.0F,
                2.0F,
                1.0F,
                0.0F
        );

        context.learningRate = 1F;
        pipeline.afterEpoch(ctx -> {
            int index = ctx.epoch;
            assertEquals(expectedGlobalLosses.get(index), context.globalLoss);
        });

        pipeline.run(context);
        assertEquals(6, context.epoch);
    }
}
