/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.commons.correctness.bdd;

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

import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.scytl.products.ov.commons.correctness.CorrectnessError;
import com.scytl.products.ov.commons.correctness.builder.options.SelectionCorrectnessBuilder;
import com.scytl.products.ov.commons.correctness.builder.options.VotingOptionCorrectnessBuilder;
import com.scytl.products.ov.commons.correctness.feedback.CorrectnessFeedback;
import com.scytl.products.ov.commons.correctness.feedback.ReportedError;
import com.scytl.products.ov.commons.correctness.internal.CorrectnessEvaluator;
import com.scytl.products.ov.commons.correctness.internal.OptionCorrectnessEvaluator;

import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;

public class OptionsSteps {

	private static final Logger LOGGER = LoggerFactory.getLogger(OptionsSteps.class);

	private VotingOptionCorrectnessBuilder correctness = new VotingOptionCorrectnessBuilder();

	private CorrectnessEvaluator<String> ce = new OptionCorrectnessEvaluator(LOGGER, false);

	private CorrectnessFeedback correctnessResult;

	private SelectionCorrectnessBuilder selectionCorrectnessBuilder;

	@Given(value = "^a voting section with name (.+), with minimum non-blank selections (\\d+) and maximum selections (\\d+) and with non-blank options (.+)$")
	public void buildCorrectness(String listName, Integer min, Integer max, String selection) {
		String[] split = selection.split(", ");
		selectionCorrectnessBuilder = correctness.withSelectionCorrectness(listName).withVotingOptions(Arrays.asList(split)).withMinSelection(min)
				.withMaxSelection(max);
	}

	@Given(value = "^a voting section with name (.+), with minimum non-blank selections (\\d+) and maximum selections (\\d+), and with blank options (.+) and with non-blank options (.+)$")
	public void buildCorrectnessWithBlank(String listName, Integer min, Integer max, String blanks, String selection) {
		List<String> split = Arrays.asList(selection.split(", "));
		List<String> blank = Arrays.asList(blanks.split(", "));
		List<String> all = new ArrayList<>();
		all.addAll(blank);
		all.addAll(split);
		selectionCorrectnessBuilder = correctness.withSelectionCorrectness(listName).withVotingOptions(all).withMinSelection(min)
				.withMaxSelection(max).withBlanks(blank);
	}
	
	@Given(value = "^allow full blank (.+)$")
	public void enableFullBlank(String fullBlank) {
		correctness.withFullBlankEnabled(Boolean.valueOf(fullBlank));
	}

	@Given(value = "^fusion with accumulation (\\d+) is defined for (.+) with values (.+)$")
	public void addFusion(Integer accumulation, String listName, String fusion) {
		List<List<String>> fusions = parseVotingOptionRelations(fusion);
		selectionCorrectnessBuilder.withAccumulation(accumulation).withFusions(fusions);
	}

	private List<List<String>> parseVotingOptionRelations(String selection) {
		String[] selections = selection.split("],");
		List<List<String>> subsections = new ArrayList<>(selections.length);
		for (String string : selections) {
			String[] split = string.replace("[", "").replace("]", "").split(", ");
			List<String> singleFusion = new ArrayList<>();
			for (String string2 : split) {
				singleFusion.add(string2.trim());
			}
			subsections.add(singleFusion);
		}
		return subsections;
	}

	@When(value = "^evaluating correctness for a ballot containing selection (.+)$")
	public void evaluateCorrectness(String selection) throws NoSuchMethodException {
		String[] split = selection.split(", ");
		correctnessResult = ce.checkCorrectness(Arrays.asList(split), correctness);
	}

	@Then(value = "^finish correctness test$")
	public void finishCorrectnessTest() {
		correctness = new VotingOptionCorrectnessBuilder();
	}

	@Then(value = "^the correctness should fail$")
	public void correctnessFailureCheck() {
		Assert.assertFalse(correctnessResult.getResult());
		Assert.assertNotNull(correctnessResult.getErrors());
	}

	@Then(value = "^the correctness should pass$")
	public void correctnessSuccessfulCheck() {
		Assert.assertTrue(correctnessResult.getResult());
		Assert.assertNull(correctnessResult.getErrors());
	}

	@Then(value = "^the error should be (.+), (.+)$")
	public void correctnessErrorReported(String errorType, String offendingPart) {
		List<ReportedError> errors = correctnessResult.getErrors();
		ReportedError found = null;
		for (ReportedError actualError : errors) {
			if(CorrectnessError.valueOf(errorType).equals(actualError.getErrorType()) &&
			offendingPart.equals(actualError.getReference())){
				found = actualError;
			}
		}
		Assert.assertNotNull(found);
		correctnessResult.getErrors().remove(found);
	}

	@Then(value = "^the error does not contain any additional messages$")
	public void noMoreReportedCorrectnessErrors() {
		if (correctnessResult.getErrors() != null) {
			Assert.assertEquals(0, correctnessResult.getErrors().size());
		}
	}
}
