package com.pingcap.community.blogserver.controller;

import com.pingcap.community.blogserver.entity.Authority;
import com.pingcap.community.blogserver.entity.Role;
import com.pingcap.community.blogserver.repository.AuthorityRepository;
import com.pingcap.community.blogserver.repository.UserRepository;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Profile("!prod")
@Tag(name = "Dev API", description = "Only available in non-production environment")
@AllArgsConstructor
@RestController
@RequestMapping("/devapi")
public class DevController {

  private final UserRepository userRepository;

  private final AuthorityRepository authorityRepository;

  @Operation(summary = "Login")
  @ResponseStatus(HttpStatus.OK)
  @GetMapping("/login")
  public void login(
    @Parameter(description = "real user id") @RequestParam Long userId,
    HttpServletRequest request,
    HttpServletResponse response
  ) throws IOException {
    var user = userRepository
      .findById(userId)
      .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));

    Set<Role> roles = user.getRoles();
    Set<Authority> userAuthorities = user.getAuthorities();
    Set<Authority> roleAuthorities = authorityRepository.findByRolesIn(roles);
    userAuthorities.addAll(roleAuthorities);

    List<GrantedAuthority> authorities = userAuthorities.stream().map(
        (authority) -> new SimpleGrantedAuthority(authority.getAuthority())
    ).collect(Collectors.toList());

    SecurityContextHolder
      .getContext()
      .setAuthentication(
        new TestingAuthenticationToken(
          user, userId, authorities
        )
      );

    // https://stackoverflow.com/questions/59126518/how-to-cope-with-x-forwarded-headers-in-spring-boot-2-2-0-spring-web-mvc-behin
    response.sendRedirect(request.getContextPath() + "/devapi/swagger-ui.html");
  }

  @Operation(summary = "Get the current principal")
  @ResponseStatus(HttpStatus.OK)
  @GetMapping("/principal")
  public Object me(@AuthenticationPrincipal Object principal) {
    return principal;
  }
}
