/*
 * 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.sdm.application.service;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.asymmetric.service.AsymmetricService;
import com.scytl.products.ov.sdm.domain.service.ConfigConstants;
import com.scytl.products.ov.sdm.infrastructure.CompositeInputStream;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Service;


import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.PrivateKey;
import java.util.List;
import java.util.stream.Collectors;

import static java.nio.file.Files.newInputStream;

@Service
public class SignatureService {

	private static final byte[] LINE_SEPARATOR = "\n".getBytes(StandardCharsets.UTF_8);

    /**
     * Signs a csv file returning the content of the signature
     * @param privateKey
     * @param csvFile
     * @return
     * @throws IOException
     * @throws GeneralCryptoLibException
     */
    public String signCSV(final PrivateKey privateKey, final File csvFile)
            throws IOException, GeneralCryptoLibException {
        final byte[] signature;
        try (FileInputStream csvFileIn = new FileInputStream(csvFile)) {

            AsymmetricService asymmetricService = new AsymmetricService();
            signature = asymmetricService.sign(privateKey, csvFileIn);
        }

        return new String(Base64.encodeBase64(signature), StandardCharsets.UTF_8);
    }


    /**
     * Creates a file containing the signature in base64 of the CSV, appending the suffix .sign
     * @param signatureB64
     * @param csvPath
     * @throws IOException
     */
    public void saveCSVSignature(final String signatureB64, final Path csvPath) throws IOException {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(csvPath.toString() + ConfigConstants.SIGN))) {
            writer.write(signatureB64);
            writer.flush();
        }
    }


    /**
     * Receives a root path and deletes all the signature files within the folder
     * @param rootPath
     * @throws IOException
     */
    public void deleteSignaturesFromCSVs(Path rootPath) throws IOException {
        List<Path> filePaths = Files.walk(rootPath, 1).collect(Collectors.toList());

        for (Path filePath : filePaths) {
            Path fileName = filePath.getFileName();
            if (fileName == null) {
                throw new IOException("Invalid file name");
            }
            String name = fileName.toString();
            if (name.endsWith(ConfigConstants.SIGN)) {
                Files.deleteIfExists(filePath);
            }

        }
    }

	public InputStream newCSVAndSignatureInputStream(final Path csvFile) throws IOException {
		Path signatureFile = csvFile.resolveSibling(csvFile.getFileName() + ConfigConstants.SIGN);
        
        InputStream signature = null;
		InputStream separator = null;
        InputStream csv = null;
        
		try {
			csv = newInputStream(csvFile);
			separator = new ByteArrayInputStream(LINE_SEPARATOR);
			signature = newInputStream(signatureFile);
		} catch (IOException e) {
			try {
				if (csv != null) {
					csv.close();
				}
				if (separator != null) {
					separator.close();
				}
			} catch (IOException e1) {
				e.addSuppressed(e1);
			}
			throw e;
		}
		return new CompositeInputStream(csv, separator, signature);
	}
}
