package com.r11.tools.interceptor;

import com.r11.tools.model.RequestHistoryDTO;
import com.r11.tools.service.RequestHistoryService;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

/**
 * Interceptor that gets needed data from HttpRequest, and saves it to history
 * @author Mikołaj Widła
 */

@Component
@AllArgsConstructor
public class IncomingMockRequestInterceptor implements HandlerInterceptor {

    private final RequestHistoryService historyService;

    @Override
    public boolean preHandle(HttpServletRequest httpRequest, HttpServletResponse response, Object handler){
        Map<String,String> headers = getHeadersFromHttpRequest(httpRequest);
        Map<String,String> pathVariable = getPathVariablesFromHttpRequest(httpRequest);
        String requestBody = getRequestBodyFromHttpRequest(httpRequest);

        RequestHistoryDTO historyDTO = RequestHistoryDTO.builder()
                .httpMethod(HttpMethod.valueOf(httpRequest.getMethod()))
                .headers( headers )
                .clientUUID(UUID.fromString(pathVariable.get("clientUUID")))
                .dateTimeStamp(LocalDateTime.now())
                .requestBody(requestBody)
                .build();
        historyService.saveRequest(historyDTO);
        return true;
    }

    private Map<String,String> getHeadersFromHttpRequest( HttpServletRequest httpRequest ){
        Set<String> headersName = StreamSupport.stream(
                Spliterators.spliteratorUnknownSize(
                        httpRequest.getHeaderNames().asIterator(),
                        Spliterator.ORDERED
                ), false
        ).collect(Collectors.toSet());

        return headersName.stream()
                .collect(Collectors.toMap(
                        value -> value,
                        httpRequest::getHeader
                ));
    }

    private Map<String,String> getPathVariablesFromHttpRequest( HttpServletRequest httpRequest ){
        return (Map<String, String>) httpRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
    }

    private String getRequestBodyFromHttpRequest( HttpServletRequest httpRequest ){
        HttpServletRequest wrappedRequest = new ContentCachingRequestWrapper(httpRequest);
        try {
            return StreamUtils.copyToString(wrappedRequest.getInputStream(), Charset.defaultCharset());
        } catch (IOException e) {
            return "";
        }
    }

}
