package com.cloudhandson.vpdbackoffice.web;

import com.cloudhandson.vpdbackoffice.domain.effective.GroupEffectiveAccessView;
import com.cloudhandson.vpdbackoffice.domain.effective.RoleEffectiveImpactView;
import com.cloudhandson.vpdbackoffice.domain.group.GroupCreateCommand;
import com.cloudhandson.vpdbackoffice.service.AppException;
import com.cloudhandson.vpdbackoffice.service.EffectiveMatrixService;
import com.cloudhandson.vpdbackoffice.service.GroupService;
import com.cloudhandson.vpdbackoffice.service.PermissionService;
import com.cloudhandson.vpdbackoffice.service.UserService;
import java.util.Map;
import java.util.stream.Collectors;
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 GroupController {

  private final GroupService groupService;
  private final UserService userService;
  private final PermissionService permissionService;
  private final EffectiveMatrixService effectiveMatrixService;

  public GroupController(
      GroupService groupService,
      UserService userService,
      PermissionService permissionService,
      EffectiveMatrixService effectiveMatrixService
  ) {
    this.groupService = groupService;
    this.userService = userService;
    this.permissionService = permissionService;
    this.effectiveMatrixService = effectiveMatrixService;
  }

  @GetMapping("/groups")
  public String groups(Model model) {
    var matrix = effectiveMatrixService.matrix();
    model.addAttribute("groups", groupService.findAll());
    model.addAttribute("users", userService.findAll());
    model.addAttribute("roles", permissionService.findRoles());
    model.addAttribute("groupUsers", groupService.findGroupUsers());
    model.addAttribute("groupRoles", groupService.findGroupRoles());
    model.addAttribute("groupImpactByGroupId", matrix.groups().stream()
        .collect(Collectors.toMap(GroupEffectiveAccessView::groupId, impact -> impact)));
    model.addAttribute("roleImpactByRoleId", matrix.roles().stream()
        .collect(Collectors.toMap(RoleEffectiveImpactView::roleId, impact -> impact)));
    return "groups";
  }

  @PostMapping("/groups")
  public String create(
      @RequestParam String groupCode,
      @RequestParam String groupName,
      @RequestParam(required = false) String description,
      RedirectAttributes redirectAttributes
  ) {
    groupService.createGroup(new GroupCreateCommand(groupCode, groupName, description));
    redirectAttributes.addFlashAttribute("message", "그룹을 추가했습니다.");
    return "redirect:/groups";
  }

  @PostMapping("/groups/active")
  public String active(
      @RequestParam long groupId,
      @RequestParam boolean active,
      @RequestParam(defaultValue = "false") boolean confirmImpact,
      RedirectAttributes redirectAttributes
  ) {
    try {
      groupService.setActive(groupId, active, active || confirmImpact);
      redirectAttributes.addFlashAttribute("message", "그룹 상태를 변경했습니다.");
    } catch (AppException exception) {
      redirectAttributes.addFlashAttribute("error", exception.getMessage());
    }
    return "redirect:/groups";
  }

  @PostMapping("/groups/users")
  public String addUser(
      @RequestParam long groupId,
      @RequestParam long userId,
      RedirectAttributes redirectAttributes
  ) {
    groupService.addUser(groupId, userId);
    redirectAttributes.addFlashAttribute("message", "그룹에 사용자를 추가했습니다.");
    return "redirect:/groups";
  }

  @PostMapping("/groups/users/delete")
  public String removeUser(
      @RequestParam long groupId,
      @RequestParam long userId,
      @RequestParam(defaultValue = "false") boolean confirmImpact,
      RedirectAttributes redirectAttributes
  ) {
    try {
      groupService.removeUser(groupId, userId, confirmImpact);
      redirectAttributes.addFlashAttribute("message", "그룹 사용자를 해제했습니다.");
    } catch (AppException exception) {
      redirectAttributes.addFlashAttribute("error", exception.getMessage());
    }
    return "redirect:/groups";
  }

  @PostMapping("/groups/roles")
  public String addRole(
      @RequestParam long groupId,
      @RequestParam long roleId,
      RedirectAttributes redirectAttributes
  ) {
    groupService.addRole(groupId, roleId);
    redirectAttributes.addFlashAttribute("message", "그룹에 역할을 부여했습니다.");
    return "redirect:/groups";
  }

  @PostMapping("/groups/roles/delete")
  public String removeRole(
      @RequestParam long groupId,
      @RequestParam long roleId,
      @RequestParam(defaultValue = "false") boolean confirmImpact,
      RedirectAttributes redirectAttributes
  ) {
    try {
      groupService.removeRole(groupId, roleId, confirmImpact);
      redirectAttributes.addFlashAttribute("message", "그룹 역할을 해제했습니다.");
    } catch (AppException exception) {
      redirectAttributes.addFlashAttribute("error", exception.getMessage());
    }
    return "redirect:/groups";
  }
}
