/*
 * 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.tallying.commons.io.writer;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.Security;
import java.util.ArrayList;
import java.util.List;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.asymmetric.service.AsymmetricService;
import com.scytl.cryptolib.primitives.service.PrimitivesService;
import com.scytl.products.oscore.logging.api.domain.Level;
import com.scytl.products.oscore.logging.api.domain.LogContent;
import com.scytl.products.oscore.logging.api.writer.LoggingWriter;
import com.scytl.products.oscore.logging.api.writer.SecureLoggingWriter;
import com.scytl.products.ov.commons.beans.Contest;
import com.scytl.products.ov.commons.sign.MetadataFileSigner;
import com.scytl.products.ov.tallying.command.TallyingHolder;
import com.scytl.products.ov.tallying.commons.HashService;
import com.scytl.products.ov.tallying.commons.beans.ContestVote;
import com.scytl.products.ov.tallying.commons.beans.OptionData;
import com.scytl.products.ov.tallying.commons.exception.TallyingException;

import mockit.Mock;
import mockit.MockUp;

public class TalliedSuccessfulVotesWriterTest {

    private final TemporaryFolder _folder = new TemporaryFolder();

    @Rule
    public TemporaryFolder getFolder() {
        return _folder;
    }

    private static TalliedSuccessfulVotesWriter _target;

    @BeforeClass
    public static void setUp() throws GeneralCryptoLibException {
        Security.addProvider(new BouncyCastleProvider());

        _target =
            new TalliedSuccessfulVotesWriter(new SignResultWriter(new MetadataFileSigner(new AsymmetricService())),
                new HashService(new PrimitivesService()), new SecureLoggingWriter() {
                    @Override
                    public void log(LogContent content) {

                    }

                    @Override
                    public void log(Level level, LogContent content, LoggingWriter loggingWriter) {

                    }

                    @Override
                    public void log(Level level, LogContent logContent) {

                    }
                });
    }

    @AfterClass
    public static void removeBouncyCastleProvider() {
        Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
    }

    @Test
    public void write_to_file_correctly() throws IOException, TallyingException {

        new MockUp<SignResultWriter>() {
            @Mock
            public void signOutput(final Path originalFilePath, final TallyingHolder holder) {

            }
        };

        List<ContestVote> contestVotes = generateContestVotes();
        TallyingHolder holder = new TallyingHolder();
        holder.setOutputDir(Paths.get(getFolder().getRoot().getAbsolutePath(), "tally"));
        holder.setContests(generateContests());
        _target.writeToFiles(contestVotes, holder);

        assertThat(getFolder().getRoot().listFiles().length, is(1));

        File tallyFolder = getFolder().getRoot().listFiles()[0];
        assertThat(tallyFolder.listFiles().length, is(3));
        List<String> resultValues0 = parseOutputCSV(new File(tallyFolder + File.separator
            + "8b0d6c721d764827b816cbf3a3f026bb" + File.separator + "8b0d6c721d764827b816cbf3a3f026bb.csv"));
        List<String> resultValues1 = parseOutputCSV(new File(tallyFolder + File.separator
            + "b858c4b828c14efeac99985ae05a94cb" + File.separator + "b858c4b828c14efeac99985ae05a94cb.csv"));
        List<String> resultValues2 = parseOutputCSV(new File(tallyFolder + File.separator
            + "doesNotContainVotes6cbf3a3f026bb" + File.separator + "doesNotContainVotes6cbf3a3f026bb.csv"));

        assertThat(resultValues0.size(), is(2));
        assertThat(resultValues1.size(), is(2));
        assertThat(resultValues2.size(), is(0));

        assertThat(resultValues0.get(0), is("4;2;3;5;7"));
        assertThat(resultValues0.get(1), is("2;2;11;23;29"));

        assertThat(resultValues1.get(0), is("1;59"));
        assertThat(resultValues1.get(1), is("9;57"));
    }

    private List<Contest> generateContests() {
        List<Contest> result = new ArrayList<>();

        addContest(result, "8b0d6c721d764827b816cbf3a3f026bb", "8b0d6c721d764827b816cbf3a3f026bb_alias");
        addContest(result, "b858c4b828c14efeac99985ae05a94cb", "b858c4b828c14efeac99985ae05a94cb_alias");
        addContest(result, "doesNotContainVotes6cbf3a3f026bb", "doesNotContainVotes6cbf3a3f026bb_alias");

        return result;
    }

    private void addContest(List<Contest> contests, String id, String alias) {
        Contest contest = new Contest(id, null, null, alias, null, null, null, null, null, null, null);
        contests.add(contest);
    }

    private List<ContestVote> generateContestVotes() {

        List<ContestVote> contestVotes = new ArrayList<>();

        ContestVote contest0 = new ContestVote("8b0d6c721d764827b816cbf3a3f026bb", new OptionData("2", null));
        contest0.add(new OptionData("3", null));
        contest0.add(new OptionData("5", null));
        contest0.add(new OptionData("7", null));
        contest0.increment();
        contest0.increment();
        contest0.increment();

        ContestVote contest1 = new ContestVote("b858c4b828c14efeac99985ae05a94cb", new OptionData("59", null));

        ContestVote contest2 = new ContestVote("8b0d6c721d764827b816cbf3a3f026bb", new OptionData("2", null));
        contest2.add(new OptionData("11", null));
        contest2.add(new OptionData("23", null));
        contest2.add(new OptionData("29", null));
        contest2.increment();

        ContestVote contest3 = new ContestVote("b858c4b828c14efeac99985ae05a94cb", new OptionData("57", null));
        contest3.increment();
        contest3.increment();
        contest3.increment();
        contest3.increment();
        contest3.increment();
        contest3.increment();
        contest3.increment();
        contest3.increment();

        contestVotes.add(contest0);
        contestVotes.add(contest1);
        contestVotes.add(contest2);
        contestVotes.add(contest3);

        return contestVotes;
    }

    private List<String> parseOutputCSV(File outputFile) throws IOException {

        List<String> results = new ArrayList<>();

        try (BufferedReader reader = new BufferedReader(new FileReader(outputFile))) {

            String currentLine;
            while ((currentLine = reader.readLine()) != null) {
                results.add(currentLine);
            }
        }

        return results;
    }
}
