package com.eactive.httpmockserver.api.controller;

import com.eactive.httpmockserver.api.dto.MockResponseDTO;
import com.eactive.httpmockserver.api.dto.MockRouteRegisterDTO;
import com.eactive.httpmockserver.api.dto.MockRouteSearch;
import com.eactive.httpmockserver.api.dto.MockRouteUpdateDTO;
import com.eactive.httpmockserver.api.entity.MockRoute;
import com.eactive.httpmockserver.api.mapper.MockRouteMapper;
import com.eactive.httpmockserver.api.service.MockRouteService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.PostConstruct;
import java.util.List;

@Controller
@RequestMapping("/mgmt/routes")
public class MockRouteMgmtController {

    private static final String MOCK_ROUTE = "mockRoute";

    @PostConstruct
    public void init() {
        mockRouteService.initAllRoutes();
    }

    private final MockRouteService mockRouteService;

    private final Validator validator;

    private final MockRouteMapper mockRouteMapper;

    private final MockApiHandlerMapping mockApiHandlerMapping;

    public MockRouteMgmtController(MockRouteService mockRouteService, Validator validator, MockRouteMapper mockRouteMapper, MockApiHandlerMapping mockApiHandlerMapping) {
        this.mockRouteService = mockRouteService;
        this.validator = validator;
        this.mockRouteMapper = mockRouteMapper;
        this.mockApiHandlerMapping = mockApiHandlerMapping;
    }

    public static final String MOCK_ROUTE_EDIT = "page/routes/mockRouteEdit";
    public static final String MOCK_ROUTE_LIST_VIEW = "redirect:/mgmt/routes/list_view.do";

    @GetMapping("/list_view.do")
    public ModelAndView listView(@ModelAttribute("mockRouteSearch") MockRouteSearch mockRouteSearch, Pageable pageable) {
        ModelAndView mav = new ModelAndView("page/routes/mockRouteList");
        Page<MockRoute> page = mockRouteService.findAll(mockRouteSearch.buildSpecification(), pageable);
        mav.addObject("page", page);
        mav.addObject("pageable", pageable);
        mav.addObject("modelSearch", mockRouteSearch);

        return mav;
    }

    @GetMapping("/create_view.do")
    public ModelAndView createView() {
        ModelAndView mav = new ModelAndView(MOCK_ROUTE_EDIT);
        MockRouteRegisterDTO defaultRoute = new MockRouteRegisterDTO();
        MockResponseDTO defaultResponse = new MockResponseDTO();
        defaultResponse.setDefaultResponse("true");
        defaultRoute.getResponses().add(defaultResponse);
        mav.addObject(MOCK_ROUTE, defaultRoute);
        return mav;
    }

    @GetMapping("/update_view.do")
    public ModelAndView updateView(@RequestParam("id") Long id) {

        ModelAndView mav = new ModelAndView(MOCK_ROUTE_EDIT);
        MockRoute found = mockRouteService.findById(id);
        mav.addObject(MOCK_ROUTE, mockRouteMapper.map(found));

        return mav;
    }

    @PostMapping("/clone_view.do")
    public ModelAndView cloneView(@RequestParam("id") Long id) {

        ModelAndView mav = new ModelAndView(MOCK_ROUTE_EDIT);
        MockRoute found = mockRouteService.findById(id);
        MockRouteRegisterDTO dto = mockRouteMapper.map(found);
        dto.setId(null);
        mav.addObject(MOCK_ROUTE, dto);

        return mav;
    }

    @PostMapping("/register.do")
    public String register(@ModelAttribute("mockRoute") MockRouteRegisterDTO dto, BindingResult bindingResult, ModelMap model) {

        if (dto == null) {
            return "redirect:/mgmt/routes/create_view.do";
        }

        validator.validate(dto, bindingResult);

        if (bindingResult.hasErrors()) {
            model.addAttribute(MOCK_ROUTE, dto);
            return MOCK_ROUTE_EDIT;
        }

        MockRoute mockRoute = mockRouteMapper.map(dto);
        mockRouteService.create(mockRoute);
        mockRouteService.initAllRoutes();
        mockApiHandlerMapping.registerMapping(mockRoute);
        return MOCK_ROUTE_LIST_VIEW;
    }


    @PostMapping("/update.do")
    public String update(@RequestParam("id") String id,
                         @ModelAttribute("mockRoute") MockRouteUpdateDTO dto,
                         BindingResult bindingResult, ModelMap model) {

        if (StringUtils.isEmpty(id)) {
            return MOCK_ROUTE_LIST_VIEW;
        }

        validator.validate(dto, bindingResult);

        if (bindingResult.hasErrors()) {
            model.addAttribute(MOCK_ROUTE, dto);
            return MOCK_ROUTE_EDIT;
        }

        MockRoute prev = mockRouteService.findById(Long.parseLong(id));
        mockApiHandlerMapping.unregisterMapping(prev);

        MockRoute mockRoute = mockRouteMapper.map(dto);
        mockRouteService.update(Long.parseLong(id), mockRoute);
        mockRouteService.initAllRoutes();

        mockApiHandlerMapping.registerMapping(mockRoute);
        return MOCK_ROUTE_LIST_VIEW;
    }


    @PostMapping("/delete.do")
    public String delete(@RequestParam("checkedIdForDel") List<String> ids) {
        for (String id : ids) {
            MockRoute mockRoute = mockRouteService.findById(Long.parseLong(id));
            mockApiHandlerMapping.unregisterMapping(mockRoute);
            mockRouteService.deleteById(Long.parseLong(id));
        }
        mockRouteService.initAllRoutes();
        return MOCK_ROUTE_LIST_VIEW;
    }
}
