/*
 * 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.config.cli;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.Security;
import java.util.Map;
import java.util.Properties;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;

import com.google.gson.Gson;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.asymmetric.service.AsymmetricService;
import com.scytl.products.ov.config.commons.ConfigPlatformRootKeyLoader;
import com.scytl.products.ov.config.commons.exception.ConfigPlatformRootException;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

import mockit.Mock;
import mockit.MockUp;

/**
 * @author rmarquez
 * @date 28/07/16 16:13 Copyright (C) 2016 All rights reserved.
 */
@RunWith(MockitoJUnitRunner.class)
public class InstallTenantCommandTest {

    private static String TENANT_ID = "100";

    private static String TENANT_CERT = "src/test/resources/testMaterial/tenantCAandKS/tenant_manolo.pem";

    private static String SYSTEM_KEYS = "src/test/resources/testMaterial/systemKeys";

    private static String PASSWORD = "AL7K6KNLNLB4KOISLK5T5U7LRA";

    private static Map<String, String> params2values;

    private static int httpPort;

    @InjectMocks
    @Spy
    private InstallTenantCommand installTenantCommand = new InstallTenantCommand();

    @BeforeClass
    public static void setUp() {
        Security.addProvider(new BouncyCastleProvider());
        String[] inputParams =
            {"-tenantid", TENANT_ID, "-tenantcert", TENANT_CERT, "-systemkeys", SYSTEM_KEYS, "-password", PASSWORD };
        params2values = Action.INSTALL_TENANT.validateAndArrange(inputParams);

    }

    @Test
    public void testRestClientHttp() {
        try {
            setupHttpServer();

            new MockUp<ConfigPlatformRootKeyLoader>() {
                @Mock
                PrivateKey getPrivateKeyFromKeystore(final String password)
                        throws ConfigPlatformRootException, GeneralCryptoLibException {
                    AsymmetricService asymmetricService = new AsymmetricService();
                    KeyPair keyPair = asymmetricService.getKeyPairForSigning();
                    return keyPair.getPrivate();
                }
            };
            new MockUp<InstallTenantCommand>() {
                @Mock
                Properties getProperties(String path) {
                    Properties properties = new Properties();
                    properties.put("AU_URL", "http://localhost:" + httpPort + "/au-ws-rest");
                    properties.put("EI_URL", "http://localhost:" + httpPort + "/ei-ws-rest");
                    properties.put("VV_URL", "http://localhost:" + httpPort + "/vv-ws-rest");
                    properties.put("CR_URL", "http://localhost:" + httpPort + "/cr-ws-rest");
                    properties.put("KT_URL", "http://localhost:" + httpPort + "/kt-ws-rest");
                    return properties;
                }
            };

            installTenantCommand.execute(params2values);

        } catch (Exception e) {
            Assert.assertTrue(false);
        }

        Assert.assertTrue(true);
    }

    public void setupHttpServer() {
        try {

            setPorts();

            // setup the socket address
            InetSocketAddress address = new InetSocketAddress(httpPort);

            // initialise the HTTP server
            HttpServer httpServer = HttpServer.create(address, 0);
            httpServer.createContext("/au-ws-rest", new MyHttpHandler());
            httpServer.createContext("/ei-ws-rest", new MyHttpHandler());
            httpServer.createContext("/vv-ws-rest", new MyHttpHandler());
            httpServer.createContext("/cr-ws-rest", new MyHttpHandler());

            httpServer.setExecutor(null); // creates a default executor
            httpServer.start();

        } catch (Exception exception) {
            System.out.println("Failed to create HTTP server on port 8080 of localhost");
            exception.printStackTrace();

        }
    }

    public static class MyHttpHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            String response = new Gson().toJson("This is the response.");
            t.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }

    private static void setPorts() throws IOException {
        httpPort = discoverFreePorts(50000, 60000);
    }

    private static int discoverFreePorts(int from, int to) throws IOException {
        int result = 0;
        ServerSocket tempServer = null;

        for (int i = from; i <= to; i++) {
            try {
                tempServer = new ServerSocket(i);
                result = tempServer.getLocalPort();
                break;

            } catch (IOException ex) {
                continue; // try next port
            }
        }

        if (result == 0) {
            throw new IOException("no free port found");
        }

        tempServer.close();
        return result;
    }

}
