package com.cloudhandson.vpdbackoffice.web;

import com.cloudhandson.vpdbackoffice.service.BearerTokenService;
import com.cloudhandson.vpdbackoffice.service.UserService;
import java.time.Clock;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.time.format.DateTimeFormatter;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@Controller
public class TokenController {

  private final BearerTokenService tokenService;
  private final UserService userService;
  private final Clock clock;

  public TokenController(BearerTokenService tokenService, UserService userService, Clock clock) {
    this.tokenService = tokenService;
    this.userService = userService;
    this.clock = clock;
  }

  @GetMapping("/tokens")
  public String tokens(
      @RequestParam(defaultValue = "false") boolean includeInactive,
      Model model
  ) {
    model.addAttribute("tokens", tokenService.findAll(includeInactive));
    model.addAttribute("includeInactive", includeInactive);
    model.addAttribute("users", userService.findAll().stream().filter(user -> user.active()).toList());
    model.addAttribute("defaultExpiresAt", defaultExpiresAt());
    return "tokens";
  }

  @PostMapping("/tokens")
  public String issue(
      @RequestParam long userId,
      @RequestParam String expiresAt,
      @RequestParam(required = false) String description,
      RedirectAttributes redirectAttributes
  ) {
    var issued = tokenService.issueToken(new com.cloudhandson.vpdbackoffice.domain.token.TokenIssueCommand(
        userId, parseBrowserDateTime(expiresAt), description));
    redirectAttributes.addFlashAttribute("issued", issued);
    return "redirect:/tokens";
  }

  @PostMapping("/tokens/revoke")
  public String revoke(
      @RequestParam long keyId,
      @RequestParam(required = false) String reason,
      RedirectAttributes redirectAttributes
  ) {
    tokenService.revokeToken(keyId, reason);
    redirectAttributes.addFlashAttribute("message", "토큰을 회수했습니다.");
    return "redirect:/tokens";
  }

  private String defaultExpiresAt() {
    return LocalDateTime.now(clock.withZone(ZoneId.systemDefault()))
        .plusMonths(1)
        .truncatedTo(ChronoUnit.MINUTES)
        .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
  }

  private OffsetDateTime parseBrowserDateTime(String expiresAt) {
    return LocalDateTime.parse(expiresAt)
        .atZone(ZoneId.systemDefault())
        .toOffsetDateTime();
  }
}
