package ru.yandex.direct.proxy.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import ru.yandex.direct.proxy.model.web.CacheStatItem;
import ru.yandex.direct.proxy.model.web.InitStepRequest;
import ru.yandex.direct.proxy.model.web.SearchResponseItem;
import ru.yandex.direct.proxy.model.web.callstep.CallStepRequest;
import ru.yandex.direct.proxy.model.web.callstep.CallStepResponse;
import ru.yandex.direct.proxy.model.web.callstep.ExecuteStepRequest;
import ru.yandex.direct.proxy.service.AliveService;
import ru.yandex.direct.proxy.service.CallStepService;
import ru.yandex.direct.proxy.service.InitStepService;
import ru.yandex.direct.proxy.service.RemoveStepService;
import ru.yandex.direct.proxy.service.SearchStepService;
import ru.yandex.direct.proxy.service.TokenStorageService;

@Controller
@RequestMapping("/")
@Api(value = "API для вызова api-steps")
public class ProxyController {
    private final InitStepService initStepService;
    private final CallStepService callStepService;
    private final RemoveStepService removeStepService;
    private final TokenStorageService tokenStorageService;
    private final SearchStepService searchStepService;
    private final AliveService aliveService;

    @Autowired
    public ProxyController(InitStepService initStepService, CallStepService callStepService,
            RemoveStepService removeStepService,
            TokenStorageService tokenStorageService,
            SearchStepService searchStepService, AliveService aliveService)
    {
        this.initStepService = initStepService;
        this.callStepService = callStepService;
        this.removeStepService = removeStepService;
        this.tokenStorageService = tokenStorageService;
        this.searchStepService = searchStepService;
        this.aliveService = aliveService;
    }

    @RequestMapping(path = "/initStep",
            method = RequestMethod.POST,
            consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(
            value = "Создание и получение токена идентифицируещего экземпляр api степов",
            nickname = "initStep",
            httpMethod = "POST"
    )
    @ApiResponses({@ApiResponse(code = 200, message = "получение токена", response = String.class)})
    @ResponseBody
    public String initStep(@RequestBody InitStepRequest initStepRequest) {
        return initStepService.initSteps(initStepRequest);
    }

    @RequestMapping(path = "/callStep",
            method = RequestMethod.POST,
            consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(
            value = "Вызов api степа",
            nickname = "callStep",
            httpMethod = "POST"
    )
    @ApiResponses({@ApiResponse(code = 200, message = "вызов степа", response = Object.class)})
    @ResponseBody
    public Object callStep(@RequestBody CallStepRequest callStepRequest) {
        return callStepService.callApiStep(callStepRequest);
    }

    @RequestMapping(path = "/callStepNew",
            method = RequestMethod.POST,
            consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(
            value = "Вызов api степа",
            nickname = "callStep",
            httpMethod = "POST"
    )
    @ApiResponses({@ApiResponse(code = 200, message = "вызов степа", response = CallStepResponse.class)})
    @ResponseBody
    public CallStepResponse callStepNew(@RequestBody CallStepRequest callStepRequest) {
        return callStepService.callStepNew(callStepRequest);
    }

    @RequestMapping(path = "/execute",
            method = RequestMethod.POST,
            consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(
            value = "Вызов api степа",
            nickname = "callStep",
            httpMethod = "POST"
    )
    @ApiResponses({@ApiResponse(code = 200, message = "вызов степа", response = CallStepResponse.class)})
    @ResponseBody
    public CallStepResponse executeStep(@RequestBody ExecuteStepRequest executeStepRequest) {
        return callStepService.executeStep(executeStepRequest);
    }


    @RequestMapping(path = "/removeStep",
            method = RequestMethod.DELETE,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(
            value = "Удаление степов по токену",
            nickname = "removeStep",
            httpMethod = "DELETE"
    )
    @ApiResponses({@ApiResponse(code = 200, message = "Удаление степов", response = Object.class)})
    @ResponseBody
    public Object removeStep(@RequestParam(value = "token") String token) {
        return removeStepService.remove(token);
    }

    @RequestMapping(path = "/alive", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiResponses({@ApiResponse(code = 200, message = "работает ли сервис", response = Boolean.class)})
    @ResponseBody
    public Boolean isAlive() {
        return aliveService.isAlive();
    }

    @RequestMapping(path = "/steps_accessible", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiResponses({@ApiResponse(code = 200, message = "работает ли сервис", response = Boolean.class)})
    @ResponseBody
    public Boolean isStepsAccessible() {
        return aliveService.stepsIsAccessible();
    }


    @RequestMapping(path = "/available_tokens", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiResponses({@ApiResponse(code = 200, message = "функцианирующие токены", response = Boolean.class)})
    @ResponseBody
    public Map<String, Object> availableTokens() {
        Map<String, Object> stats = new HashMap<>();
        stats.put("stats", CacheStatItem.fromCacheStat(tokenStorageService.getStats()));
        stats.put("tokens", tokenStorageService.getAllSteps());
        return stats;
    }

    @RequestMapping(path = "/search",
            method = RequestMethod.POST,
            consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(
            value = "Получение степа с аргументами",
            nickname = "callStep",
            httpMethod = "POST"
    )
    @ApiResponses({@ApiResponse(code = 200, message = "вызов степа", response = CallStepResponse.class)})
    @ResponseBody
    public List<SearchResponseItem> search(@RequestParam(value = "steps") List<String> substrings) {
        return searchStepService.search(substrings);
    }
}
