/*
 * 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 static org.mockito.Mockito.anyMapOf;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;

import com.scytl.products.ov.commons.infrastructure.remote.client.RetrofitException;
import com.scytl.products.ov.sdm.domain.model.votingcardset.VotingCardSetRepository;
import com.scytl.products.ov.sdm.infrastructure.cc.ChoiceCodeGenerationRequestPayloadRepository;
import com.scytl.products.ov.sdm.infrastructure.cc.PayloadStorageException;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

@RunWith(MockitoJUnitRunner.class)
public class ChoiceCodesComputationServiceTest {
    
    final String orUrl = "http://localhost:%s/ag-ws-rest/or";
    
    private final static String VCS_LIST = "{\"result\":[{\"verificationCardSetId\":\"123\", \"status\":\"COMPUTING\"}]}"; 
    
    private static int httpPort;
    
    @Mock
    private VotingCardSetRepository votingCardSetRepository;
    
    @Mock
    private ChoiceCodeGenerationRequestPayloadRepository choiceCodeGenerationRequestPayloadRepository;

    @InjectMocks
    public ChoiceCodesComputationService choiceCodesComputationService = new ChoiceCodesComputationService();

    @Test
    public void updateComputationStatusComputed() throws RetrofitException, IOException, PayloadStorageException {
        setupHttpServer();
        
        ReflectionTestUtils.setField(choiceCodesComputationService, "tenantId", "100");

        String finalUrl = String.format(orUrl, httpPort);
        ReflectionTestUtils.setField(choiceCodesComputationService, "orchestratorUrl", finalUrl);
        
        when(votingCardSetRepository.list(anyMapOf(String.class, Object.class))).thenReturn(VCS_LIST);
        
        String electionEventId = "abcd";
        when(choiceCodeGenerationRequestPayloadRepository.getCount(electionEventId, "123")).thenReturn(1);
        
        choiceCodesComputationService.updateChoiceCodesComputationStatus(electionEventId);
        
        verify(votingCardSetRepository).update("{\"verificationCardSetId\":\"123\",\"status\":\"COMPUTED\"}");
    }
    
    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("/", 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();

        }
    }
    
    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;
    }

    public static class MyHttpHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            String response = "{\"status\":\"COMPUTED\"}";
            t.getResponseHeaders().add("Content-Type", "application/json");
            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }

}
