package premium_store.controller.controller;

import premium_store.configuration.OpenAPI30Configuration;
import premium_store.controller.DTO.ClientDTO;
import premium_store.controller.DTO.UserSignupDto;
import premium_store.model.GameClient;
import premium_store.model.UserRole;
import premium_store.service.GameClientService;
import premium_store.service.TankService;

import org.springframework.data.domain.Page;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.ValidationException;
import java.util.List;
import java.util.stream.IntStream;

@RestController
public class GameClientController {
    public static final String URL_LOGIN = "/jwt/login";
    public static final String URL_SING_UP = "/sing_up";
    public static final String URL_WHO_AM_I = "/who_am_i";

    private final GameClientService gameClientService;
    private final TankService tankService;

    public GameClientController(GameClientService gameClientService, TankService tankService){
        this.gameClientService = gameClientService;
        this.tankService = tankService;
    }

    @PostMapping(URL_LOGIN)
    public String login(@RequestBody @Valid ClientDTO userDto) {
        return gameClientService.loginAndGetToken(userDto);
    }

    @PostMapping(URL_SING_UP)
    public String singUp(@RequestBody @Valid UserSignupDto userSignupDto) {
        try {
            final GameClient user = gameClientService.addClient(userSignupDto.getLogin(), userSignupDto.getEmail(), userSignupDto.getPassword(),
                    Integer.parseInt(userSignupDto.getBalance()), userSignupDto.getPasswordConfirm(), UserRole.USER);

            return "created " + user.getLogin();
        } catch (ValidationException e) {
            return e.getMessage();
        }
    }

    //аннотация PathVariable связывает значения id из URL и Long id
    @GetMapping(OpenAPI30Configuration.API_PREFIX + "/")
    public ClientDTO getClient(@PathVariable Long id) {
        return new ClientDTO(gameClientService.findClient(id));
    }

    @PutMapping(OpenAPI30Configuration.API_PREFIX + "/{id}")
    @Secured({UserRole.AsString.USER})
    public ClientDTO updateClient(@PathVariable Long id,
                                  @RequestParam("login") String login,
                                  @RequestParam("password") String password,
                                  @RequestParam("email") String email,
                                  @RequestParam("balance") Integer balance,
                                  @RequestParam("tankId") Long tankId) {
        return new ClientDTO(gameClientService.updateClient(id, login, password, email, balance, tankService.findTank(tankId)));
    }

    @PostMapping(OpenAPI30Configuration.API_PREFIX + "/{id}")
    @Secured({UserRole.AsString.USER})
    public ClientDTO deleteClient(@PathVariable Long id) {
        return new ClientDTO(gameClientService.deleteClient(id));
    }

    @GetMapping(OpenAPI30Configuration.API_PREFIX + "/users")
    @Secured({UserRole.AsString.ADMIN})
    public Pair<Page<ClientDTO>, List<Integer>> getClients(@RequestParam(defaultValue = "1") int page,
                                                       @RequestParam(defaultValue = "5") int size) {
        final Page<ClientDTO> users = gameClientService.findAllPages(page, size)
                .map(ClientDTO::new);

        final int totalPages = users.getTotalPages();

        final List<Integer> pageNumbers = IntStream.rangeClosed(1, totalPages)
                .boxed()
                .toList();

        return new Pair<>(users, pageNumbers);
    }

    @GetMapping(URL_WHO_AM_I)
    public String whoAmI(@RequestParam("token") String token) {
        UserDetails userDetails = gameClientService.loadUserByToken(token);
        GameClient user = gameClientService.findByLogin(userDetails.getUsername());
        return user.getRole().toString();
    }
}
