package com.telephoners.krakyournet.ctf.beans.tasks;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.telephoners.krakyournet.ctf.beans.Flag;
import com.telephoners.krakyournet.ctf.helpers.StreamUtils;
import org.apache.http.Header;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.mongodb.morphia.annotations.Entity;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Entity("tasks")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class WebTask extends Task
{
    private String url;

    public WebTask(String name, int level, String description, List<Flag> flags, String url)
    {
        super(name, level, description, flags);
        this.url = url;
    }

    public WebTask()
    {
    }

    //todo: avoid converting in both ways
    private Map<String, String> buildHeadersMap(Header[] headers)
    {
        return Stream.of(headers)
                .collect(Collectors.toMap(
                        Header::getName,
                        Header::getValue
                ));
    }

    private Header[] buildHeadersArray(Map<String, String> headers)
    {
        List<BasicHeader> headersList = headers.entrySet().stream() //todo: dirty casting
                .map(headerEntry -> new BasicHeader(headerEntry.getKey(), headerEntry.getValue()))
                .collect(Collectors.toList());
        Header[] headersArray = new Header[headersList.size()];
        return headersList.toArray(headersArray);
    }

    @Override
    public TaskResponse getTaskResponse(TaskRequestContext taskRequestContext) throws IOException
    {
        String proxiedUrl = getTaskUrl() + taskRequestContext.getPath();
        CloseableHttpResponse response = proxyRequest(proxiedUrl, taskRequestContext);
        String text = StreamUtils.readStream(response.getEntity().getContent());
        return new TaskResponse(text, buildHeadersMap(response.getAllHeaders()));
    }

    public String getTaskUrl()
    {
        return url;
    }

    public void setUrl(String url)
    {
        this.url = url;
    }

    private CloseableHttpResponse proxyRequest(String url, TaskRequestContext taskRequestContext) throws IOException
    {
        CloseableHttpClient httpClient = HttpClients.createDefault();

        HttpMethod httpMethod = taskRequestContext.getHttpMethod();
        if (httpMethod.equals(HttpMethod.GET)) {
            HttpGet httpget = new HttpGet(url);
            httpget.setHeaders(buildHeadersArray(taskRequestContext.getHeaders()));
            return httpClient.execute(httpget);
        } else if (httpMethod.equals(HttpMethod.POST)) {
            HttpPost httpPost = new HttpPost(url);
            httpPost.setHeaders(buildHeadersArray(taskRequestContext.getHeaders()));
            httpPost.setEntity(new ByteArrayEntity(taskRequestContext.getBody().getBytes("UTF-8")));
            return httpClient.execute(httpPost);
        } else {
            throw new IllegalStateException("Invalid http method");
        }

    }
}
