package cz.muni.disa.adamiss.se;

import cz.muni.disa.adamiss.core.common.enums.ParameterName;
import cz.muni.disa.adamiss.core.objects.Operator;
import cz.muni.disa.adamiss.core.objects.TransactionFile;
import cz.muni.disa.adamiss.se.common.Algo;
import cz.muni.disa.adamiss.se.common.Dataset;
import cz.muni.disa.adamiss.se.operators.GSP;
import cz.muni.disa.adamiss.se.operators.PrefixSpan;
import cz.muni.disa.adamiss.se.operators.Spam;
import cz.muni.disa.adamiss.se.stats.objects.DBReport;
import cz.muni.disa.adamiss.se.stats.objects.ExperimentReport;
import cz.muni.disa.adamiss.se.structures.DatasetContainer;
import javafx.util.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Ignore;
import org.junit.Test;

import java.text.SimpleDateFormat;
import java.util.*;

public class MainTest {

    Logger logger = LogManager.getLogger(MainTest.class);

/*
    @Test
    @Ignore
    public void MainTest(){
        logger.debug("Loading datasets.");
        List<Pair<String, TransactionFile>> datasets = Main.getDatasets();

        logger.debug("Analysing datasets.");
        List<DatasetContainer> containers = new ArrayList<>();
        List<DBReport> reports = new ArrayList<>();
        for (var pair : datasets) {
            logger.debug("Analysing: " + pair.getKey());
            DBReport report = Main.getDatabaseStats(pair.getKey(), pair.getValue());
            reports.add(report);

            containers.add(new DatasetContainer(pair.getKey(), pair.getValue(), report));
        }

        SimpleDateFormat formatter = new SimpleDateFormat();
        String outputFileDate = formatter.format(new Date());

        logger.debug("Saving dataset stats.");
        String dbReportCSV = DBReport.toCSVWithHeader(reports);
        Main.saveAsCSV(dbReportCSV.toString(), "DatasetStats" + outputFileDate);
    }*/
/*
    @Test
    @Ignore
    public void EqualityTest(){
        Operator GSP = new GSP();
        Operator PrefexSpan = new PrefixSpan();
        Operator Spam = new Spam();

        List<Pair<String, TransactionFile>> datasets  = Main.getDatasets("SIGN");

        Map<String, Object> params = new HashMap<>();
        params.put(ParameterName.miningThreshold.toString(), Dataset.BIBLE.getSupports()[0]);

        var result1 = GSP.apply(datasets.get(0).getValue(), params);
        var result2 = PrefexSpan.apply(datasets.get(0).getValue(), params);
        var result3 = Spam.apply(datasets.get(0).getValue(), params);

        assert result1.equals(result2) && result1.equals(result3) && result2.equals(result3);

    }*/

    public static ExperimentReport run(String name, DatasetContainer container, Algo algo) {

        long time = Long.MAX_VALUE;
        TransactionFile result = new TransactionFile(new ArrayList<>());
        int threshold = cache.containsKey(container.name())? cache.get(container.name())+1 : container.dataset().getTransactions().size();

        while(result.getTransactions().isEmpty()) {
            threshold--;
            Map<String, Object> params = new HashMap<>();
            params.put(ParameterName.miningThreshold.toString(), threshold);
            Operator operator;
            switch (algo) {
                case GSP -> operator = new GSP();
                case PREFIX_SPAN -> operator = new PrefixSpan();
                case SPAM -> operator = new Spam();
                //case SPADE -> operator = new Spade();
                default -> throw new IllegalStateException("Unexpected value: " + algo);
            }

            long startTime = System.currentTimeMillis();
            result = operator.apply(container.dataset(), params);
            time = System.currentTimeMillis() - startTime;
        }

        cache.put(container.name(), threshold);
        return new ExperimentReport(name, container.dbReport(), threshold, time, algo);
    }


    private static Map<String, Integer> cache = new HashMap<>();
}
