package com.eactive.testmaster.api.controller;

import com.eactive.testmaster.api.entity.MockRoute;
import com.eactive.testmaster.api.service.MockRouteService;
import com.eactive.testmaster.config.CsrfExclusionService;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

@Component
public class MockApiHandlerMapping {

    private static final Logger logger = LoggerFactory.getLogger(MockApiHandlerMapping.class);

    @Autowired
    private MockRouteService mockRouteService;

    @Autowired
    private MockApiController mockApiController;

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Autowired
    private CsrfExclusionService csrfExclusionService;

    @PostConstruct
    public void initialize() {
        mockRouteService.initAllRoutes();
        for (MockRoute mockRoute : mockRouteService.getAllRoutes()) {
            registerMapping(mockRoute);
        }
    }

    public void registerMapping(MockRoute mockRoute) {
        RequestMappingInfo mappingInfo = RequestMappingInfo
                .paths(mockRoute.getPathPattern())
                .methods(RequestMethod.valueOf(mockRoute.getMethod()))
                .build();

        try {
            requestMappingHandlerMapping.registerMapping(mappingInfo, mockApiController, MockApiController.class.getDeclaredMethod("handleRequest", HttpServletRequest.class));
            if (mockRoute.getMethod().equalsIgnoreCase("POST") || mockRoute.getMethod().equalsIgnoreCase("PUT")) {
                csrfExclusionService.addExcludedPath(mockRoute.getPathPattern());
            }
            logger.info("Registered mapping for {} {}", mockRoute.getMethod(), mockRoute.getPathPattern());
        } catch (NoSuchMethodException e) {
            logger.error("Error registering mapping", e);
        }
    }

    public void unregisterMapping(MockRoute mockRoute) {
        RequestMappingInfo mappingInfo = RequestMappingInfo
                .paths(mockRoute.getPathPattern())
                .methods(RequestMethod.valueOf(mockRoute.getMethod()))
                .build();
        if (mockRoute.getMethod().equalsIgnoreCase("POST") || mockRoute.getMethod().equalsIgnoreCase("PUT")) {
            csrfExclusionService.removeExcludedPath(mockRoute.getPathPattern());
        }
        requestMappingHandlerMapping.unregisterMapping(mappingInfo);
        logger.info("Unregistered mapping for {} {}", mockRoute.getMethod(), mockRoute.getPathPattern());
    }
}
