package eu.dnetlib.validator2.engine;

import com.google.gson.Gson;
import eu.dnetlib.validator2.validation.XMLApplicationProfile;
import eu.dnetlib.validator2.validation.guideline.Guideline;
import eu.dnetlib.validator2.validation.guideline.openaire.AbstractOpenAireProfile;
import eu.dnetlib.validator2.validation.guideline.openaire.LiteratureGuidelinesV4Profile;
import eu.dnetlib.validator2.validation.utils.TestUtils;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;

import javax.xml.parsers.DocumentBuilder;
import java.io.BufferedWriter;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.OptionalDouble;
import java.util.stream.Collectors;

public class Test_v4 {

    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Test_v4.class);

    public static final String TEST_FILES_V4_DIR = TestUtils.TEST_FILES_BASE_DIR + "openaireguidelinesV4/";

    private static final String[] FILES = new String[] {
//            TEST_FILES_V4_DIR + "v4_literature_all_invalid_guidelines_record.xml",
//            TEST_FILES_V4_DIR + "v4_literature_all_guidelines_record.xml",
//            TEST_FILES_V4_DIR + "oai_mediarep_org_doc_2534.xml",
            TEST_FILES_V4_DIR + "01_gv4.xml"
    };


    public static void main(String[] args) {
        // String xmlFile = args[0];
        AbstractOpenAireProfile profile = new LiteratureGuidelinesV4Profile();
        logger.info("Max score: " + profile.maxScore());
        Map<String, Double> scorePerDoc = new LinkedHashMap<>();
        DocumentBuilder builder = TestUtils.getDocumentBuilder();
        if ( builder == null )
            return;

        final Gson gson = new Gson();

        for ( String fileName : FILES ) {
            try {
                logger.info("Processing \"" + fileName + "\"");
                Document doc = builder.parse(new File(fileName));
                XMLApplicationProfile.ValidationResult result = profile.validate(fileName, doc);

                // Test writing to json-file.
                //////////////////////////////////////////
                String resultsFile = System.getProperty("user.dir") + File.separator + "results_v4.json";
                logger.info("Will append the results into the results-file: " + resultsFile);
                try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(resultsFile), StandardCharsets.UTF_8)) {
                    writer.append("\n");
                    writer.append(gson.toJson(result));
                } catch (Exception e) {
                    logger.error("Error when writing the \"ValidationResult\" as json into the results-file: " + resultsFile);
                    return;
                }
                /////////////////////////////////////////

                scorePerDoc.put(fileName, result.getScore());
                Map<String, Guideline.Result> results = result.getResults();
                for ( Map.Entry<String, Guideline.Result> entry : results.entrySet() ) {
                    String key = entry.getKey();
                    Guideline.Result value = entry.getValue();
                    logger.debug(key + " = " + value);
                    if ( key.contains("Date")) {
                        logger.info("Warnings: " + results.get(key).getWarnings().toString());
                        logger.info("Errors: " + results.get(key).getErrors().toString());
                        logger.info("Result: " + key + " = " + value + "\n");
                    }
                }
            } catch (Exception e) {
                logger.error("", e);
            }
        }

        // Individual scores
        String printout = scorePerDoc.entrySet().stream().
                map(entry -> entry.getValue() + ": " + entry.getKey()).collect(Collectors.joining("\n"));

        logger.info(printout);

        // Average Score
        OptionalDouble optionalFinalScore = scorePerDoc.values().stream().mapToDouble(aDouble -> aDouble).average();
        double finalScore = (optionalFinalScore.isPresent() ? optionalFinalScore.getAsDouble() : -1 );

        logger.info("Validation Score: " + finalScore);
    }

}
