package io.aiven.klaw.service;

import static io.aiven.klaw.error.KlawErrorMessages.TEAMS_ERR_102;
import static io.aiven.klaw.error.KlawErrorMessages.TEAMS_ERR_106;
import static io.aiven.klaw.error.KlawErrorMessages.TEAMS_ERR_109;
import static io.aiven.klaw.error.KlawErrorMessages.TEAMS_ERR_114;
import static io.aiven.klaw.error.KlawErrorMessages.TEAMS_ERR_115;
import static io.aiven.klaw.error.KlawErrorMessages.TEAMS_ERR_117;
import static io.aiven.klaw.error.KlawErrorMessages.TEAMS_ERR_119;
import static io.aiven.klaw.error.KlawErrorMessages.TEAMS_ERR_120;
import static io.aiven.klaw.helpers.KwConstants.PASSWORD_REGEX_VALIDATION_STR;
import static io.aiven.klaw.helpers.KwConstants.SUPERADMIN_ROLE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;

import io.aiven.klaw.UtilMethods;
import io.aiven.klaw.config.ManageDatabase;
import io.aiven.klaw.dao.Env;
import io.aiven.klaw.dao.RegisterUserInfo;
import io.aiven.klaw.dao.Team;
import io.aiven.klaw.dao.UserInfo;
import io.aiven.klaw.error.KlawErrorMessages;
import io.aiven.klaw.error.KlawException;
import io.aiven.klaw.error.KlawNotAuthorizedException;
import io.aiven.klaw.helpers.KwConstants;
import io.aiven.klaw.helpers.db.rdbms.HandleDbRequestsJdbc;
import io.aiven.klaw.model.ApiResponse;
import io.aiven.klaw.model.enums.ApiResultStatus;
import io.aiven.klaw.model.enums.AuthenticationType;
import io.aiven.klaw.model.enums.EntityType;
import io.aiven.klaw.model.enums.MetadataOperationType;
import io.aiven.klaw.model.enums.NewUserStatus;
import io.aiven.klaw.model.enums.PermissionType;
import io.aiven.klaw.model.requests.ChangePasswordRequestModel;
import io.aiven.klaw.model.requests.ProfileModel;
import io.aiven.klaw.model.requests.RegisterUserInfoModel;
import io.aiven.klaw.model.requests.TeamModel;
import io.aiven.klaw.model.requests.UserInfoModel;
import io.aiven.klaw.model.response.RegisterUserInfoModelResponse;
import io.aiven.klaw.model.response.ResetPasswordInfo;
import io.aiven.klaw.model.response.TeamModelResponse;
import io.aiven.klaw.model.response.UserInfoModelResponse;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Stream;
import org.jasypt.util.text.BasicTextEncryptor;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.platform.commons.util.StringUtils;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.util.ReflectionTestUtils;

@ExtendWith(SpringExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UsersTeamsControllerServiceTest {

  public static final String OCTOPUS = "octopus";
  private static final int TEST_TENANT_ID = 101;
  private static final int TEST_TEAM_ID = 3;
  private static final String TEST_TENANT_NAME = "testTenantName";
  private static final String TEST_NEW_USER_UNAME = "newUserUname";
  private static final String ENCRYPTOR_SECRET_KEY = "encryptorSecretKey";
  private static final String TEST_NEW_USER_PWD_PLAIN_TEXT = "newUserPwd";
  private static final String TEST_AUTHENTICATED_USER_UNAME = "authenticatedUserName";
  private static final String TEST_LOGIN_URL = "http://klaw.com/login";
  public static final String BCRYPT_ENCODING_ID = "{bcrypt}";
  private UtilMethods utilMethods;

  private static Validator validator;

  @Mock InMemoryUserDetailsManager inMemoryUserDetailsManager;
  @Mock private MailUtils mailService;

  @Mock private HandleDbRequestsJdbc handleDbRequests;
  @Mock private CommonUtilsService commonUtilsService;
  @Mock private PasswordService passwordService;
  @Mock private UserDetails userDetails;
  @Mock private ManageDatabase manageDatabase;
  @Mock private BCryptPasswordEncoder bcryptPasswordEncoder;

  private UsersTeamsControllerService usersTeamsControllerService;
  private UserInfo userInfo;
  private RegisterUserInfo testNewRegUser;
  private ArgumentCaptor<Team> teamCaptor;
  private ArgumentCaptor<UserDetails> userDetailsArgCaptor;
  private ArgumentCaptor<UserInfo> userInfoArgCaptor;
  private ArgumentCaptor<String> stringArgCaptor;

  @BeforeEach
  public void setUp() {
    utilMethods = new UtilMethods();
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    validator = factory.getValidator();
    usersTeamsControllerService = new UsersTeamsControllerService();
    teamCaptor = ArgumentCaptor.forClass(Team.class);
    userDetailsArgCaptor = ArgumentCaptor.forClass(UserDetails.class);
    userInfoArgCaptor = ArgumentCaptor.forClass(UserInfo.class);
    stringArgCaptor = ArgumentCaptor.forClass(String.class);
    testNewRegUser =
        utilMethods.getRegisterUserInfoMock(
            TEST_NEW_USER_UNAME, encodePwd(TEST_NEW_USER_PWD_PLAIN_TEXT));
    ReflectionTestUtils.setField(
        usersTeamsControllerService, "inMemoryUserDetailsManager", inMemoryUserDetailsManager);
    ReflectionTestUtils.setField(usersTeamsControllerService, "manageDatabase", manageDatabase);
    ReflectionTestUtils.setField(usersTeamsControllerService, "mailService", mailService);
    ReflectionTestUtils.setField(
        usersTeamsControllerService, "commonUtilsService", commonUtilsService);
    ReflectionTestUtils.setField(usersTeamsControllerService, "passwordService", passwordService);
    ReflectionTestUtils.setField(passwordService, "encryptorSecretKey", ENCRYPTOR_SECRET_KEY);
    ReflectionTestUtils.setField(
        passwordService,
        "passwordEncoder",
        PasswordEncoderFactories.createDelegatingPasswordEncoder());
    when(manageDatabase.getHandleDbRequests()).thenReturn(handleDbRequests);
    userInfo = utilMethods.getUserInfoMockDao();

    when(commonUtilsService.getPrincipal()).thenReturn(userDetails);
    when(commonUtilsService.isNotAuthorizedUser(any(), any(PermissionType.class))).thenReturn(true);
    when(passwordService.getBcryptPassword(any())).thenCallRealMethod();
    when(passwordService.encodePwd(any())).thenCallRealMethod();
    when(commonUtilsService.getJasyptEncryptor()).thenCallRealMethod();
  }

  @Test
  public void getUserInfoDetails() {
    String userId = "testuser";
    when(handleDbRequests.getUsersInfo(anyString())).thenReturn(userInfo);
    when(manageDatabase.getTeamNameFromTeamId(anyInt(), anyInt())).thenReturn("testteam");
    UserInfoModelResponse userInfoModel = usersTeamsControllerService.getUserInfoDetails(userId);
    assertThat(userInfoModel.getTeamId()).isEqualTo(userInfo.getTeamId());
    assertThat(userInfoModel.getUsername()).isEqualTo(userInfo.getUsername());
    assertThat(userInfoModel.getRole()).isEqualTo(userInfo.getRole());
    assertThat(userInfoModel.getTeam()).isEqualTo("testteam");
  }

  @Test
  public void updateProfile() throws KlawException {
    ProfileModel userInfoModel = utilMethods.getUserInfoToUpdateMock();
    when(handleDbRequests.getUsersInfo(anyString())).thenReturn(userInfo);
    when(mailService.getUserName(any())).thenReturn("kwusera");
    when(handleDbRequests.updateUser(any())).thenReturn(ApiResultStatus.SUCCESS.value);
    ApiResponse apiResponse = usersTeamsControllerService.updateProfile(userInfoModel);
    assertThat(apiResponse.getMessage()).isEqualTo(ApiResultStatus.SUCCESS.value);
  }

  @Test
  public void updateProfileFailureDbUpdate() {
    ProfileModel userInfoModel = utilMethods.getUserInfoToUpdateMock();
    when(handleDbRequests.getUsersInfo(anyString())).thenReturn(userInfo);
    when(mailService.getUserName(any())).thenReturn("kwusera");
    when(handleDbRequests.updateUser(any())).thenThrow(new RuntimeException("Db update failed"));
    KlawException thrown =
        Assertions.assertThrows(
            KlawException.class, () -> usersTeamsControllerService.updateProfile(userInfoModel));
    assertThat(thrown.getMessage()).isEqualTo("Db update failed");
  }

  @Test
  public void updateUserNotAuthorized() throws KlawException {
    UserInfoModel userInfoModel = utilMethods.getUserInfoMock();
    ApiResponse apiResponse = usersTeamsControllerService.updateUser(userInfoModel);
    assertThat(apiResponse.getMessage()).isEqualTo(ApiResultStatus.NOT_AUTHORIZED.value);
  }

  @Test
  public void notAuthorizedToUpdateUserWithSpecificPermissions() throws KlawException {
    final String userName = "testUser";
    UserInfoModel userInfoModel = utilMethods.getUserInfoMock();
    when(commonUtilsService.isNotAuthorizedUser(userName, PermissionType.ADD_EDIT_DELETE_USERS))
        .thenReturn(false);
    when(handleDbRequests.getUsersInfo(anyString())).thenReturn(userInfo);
    when(commonUtilsService.getTenantId(anyString())).thenReturn(101);
    when(mailService.getUserName(userDetails)).thenReturn(userName);
    when(manageDatabase.getRolesPermissionsPerTenant(anyInt()))
        .thenReturn(utilMethods.getRolesPermsMapForSuperuser());
    ApiResponse apiResponse = usersTeamsControllerService.updateUser(userInfoModel);
    assertThat(apiResponse.getMessage())
        .isEqualTo("Not Authorized to update another SUPERADMIN user.");
  }

  @Test
  public void notAuthorizedToUpdateSuperAdmin() throws KlawException {
    final String userName = "testUser";
    UserInfoModel userInfoModel = utilMethods.getUserInfoMock();
    userInfoModel.setRole(SUPERADMIN_ROLE);
    when(commonUtilsService.isNotAuthorizedUser(userName, PermissionType.ADD_EDIT_DELETE_USERS))
        .thenReturn(false);
    when(handleDbRequests.getUsersInfo(anyString())).thenReturn(userInfo);
    when(commonUtilsService.getTenantId(anyString())).thenReturn(101);
    when(mailService.getUserName(userDetails)).thenReturn(userName);
    ApiResponse apiResponse = usersTeamsControllerService.updateUser(userInfoModel);
    assertThat(apiResponse.getMessage()).isEqualTo(TEAMS_ERR_102);
  }

  @Test
  public void updateSuperAdminSuccessWithPermissions() throws KlawException {
    final String userName = "testUser";
    UserInfoModel userInfoModel = utilMethods.getUserInfoMock();
    userInfoModel.setRole(SUPERADMIN_ROLE);
    when(commonUtilsService.isNotAuthorizedUser(userName, PermissionType.ADD_EDIT_DELETE_USERS))
        .thenReturn(false);
    when(commonUtilsService.isNotAuthorizedUser(userName, PermissionType.UPDATE_PERMISSIONS))
        .thenReturn(false);
    when(handleDbRequests.getUsersInfo(anyString())).thenReturn(userInfo);
    when(commonUtilsService.getTenantId(anyString())).thenReturn(101);
    when(mailService.getUserName(userDetails)).thenReturn(userName);

    when(handleDbRequests.updateUser(any())).thenReturn(ApiResultStatus.SUCCESS.value);
    ApiResponse apiResponse = usersTeamsControllerService.updateUser(userInfoModel);
    assertThat(apiResponse.getMessage()).isEqualTo(ApiResponse.SUCCESS.getMessage());
  }

  @Test
  public void resetPassword_withSuccess() throws KlawException, KlawNotAuthorizedException {
    String newPW = "newPW321@";
    String resetToken = UUID.randomUUID().toString();
    when(handleDbRequests.getUsersInfo(eq(OCTOPUS))).thenReturn(generateUser(OCTOPUS));
    when(manageDatabase.getTeamNameFromTeamId(eq(101), eq(10))).thenReturn("Octo");
    when(handleDbRequests.resetPassword(eq(OCTOPUS), eq(resetToken), anyString()))
        .thenReturn(ApiResultStatus.SUCCESS.value);
    when(inMemoryUserDetailsManager.loadUserByUsername(eq(OCTOPUS)))
        .thenReturn(userDetails(OCTOPUS, newPW));
    ResetPasswordInfo passwordReset =
        usersTeamsControllerService.resetPassword(OCTOPUS, newPW, resetToken);

    verify(handleDbRequests, times(1)).resetPassword(eq(OCTOPUS), eq(resetToken), anyString());
    verify(inMemoryUserDetailsManager, times(1))
        .updatePassword(any(UserDetails.class), anyString());
    assertThat(passwordReset.isUserFound()).isEqualTo(true);
    assertThat(passwordReset.isTokenSent()).isEqualTo(true);
  }

  @Test
  public void resetPassword_withFailure() throws KlawNotAuthorizedException {
    String newPW = "newPW";
    String resetToken = UUID.randomUUID().toString();
    when(handleDbRequests.getUsersInfo(eq(OCTOPUS))).thenReturn(generateUser(OCTOPUS));
    when(manageDatabase.getTeamNameFromTeamId(eq(101), eq(10))).thenReturn("Octo");
    when(handleDbRequests.resetPassword(eq(OCTOPUS), eq(resetToken), anyString()))
        .thenReturn(ApiResultStatus.FAILURE.value);
    when(inMemoryUserDetailsManager.loadUserByUsername(eq(OCTOPUS)))
        .thenReturn(userDetails(OCTOPUS, newPW));
    ResetPasswordInfo passwordReset =
        usersTeamsControllerService.resetPassword(OCTOPUS, newPW, resetToken);
    verify(handleDbRequests, times(1)).resetPassword(eq(OCTOPUS), eq(resetToken), anyString());
    verify(inMemoryUserDetailsManager, times(0))
        .updatePassword(any(UserDetails.class), anyString());
    assertThat(passwordReset.isUserFound()).isTrue();
    assertThat(passwordReset.isTokenSent()).isFalse();
  }

  @Test
  public void resetPassword_noUser() throws KlawNotAuthorizedException {
    String newPW = "newPW";
    String resetToken = UUID.randomUUID().toString();
    when(handleDbRequests.getUsersInfo(eq(OCTOPUS))).thenReturn(null);

    ResetPasswordInfo passwordReset =
        usersTeamsControllerService.resetPassword(OCTOPUS, newPW, resetToken);

    assertThat(passwordReset.isUserFound()).isEqualTo(false);
    assertThat(passwordReset.isTokenSent()).isEqualTo(false);
  }

  @Test
  public void resetPasswordGenerateToken_noUser() throws KlawException {
    String newPW = "newPW";
    String resetToken = UUID.randomUUID().toString();
    when(handleDbRequests.getUsersInfo(eq(OCTOPUS))).thenReturn(null);

    ResetPasswordInfo passwordReset =
        usersTeamsControllerService.resetPasswordGenerateToken(OCTOPUS);

    assertThat(passwordReset.isUserFound()).isEqualTo(false);
    assertThat(passwordReset.isTokenSent()).isEqualTo(false);
  }

  @Test
  public void resetPasswordGenerateToken_withSuccess() throws KlawException {
    String resetToken = UUID.randomUUID().toString();
    when(handleDbRequests.getUsersInfo(eq(OCTOPUS))).thenReturn(generateUser(OCTOPUS));
    when(manageDatabase.getTeamNameFromTeamId(eq(101), eq(10))).thenReturn("Octo");
    when(handleDbRequests.generatePasswordResetToken(OCTOPUS)).thenReturn(resetToken);

    ResetPasswordInfo resetInfo = usersTeamsControllerService.resetPasswordGenerateToken(OCTOPUS);
    assertThat(resetInfo.isUserFound()).isEqualTo(true);
    assertThat(resetInfo.isTokenSent()).isEqualTo(true);
  }

  @Test
  public void resetPasswordGenerateToken_withFailure() throws KlawException {

    when(handleDbRequests.getUsersInfo(eq(OCTOPUS))).thenReturn(generateUser(OCTOPUS));
    when(manageDatabase.getTeamNameFromTeamId(eq(101), eq(10))).thenReturn("Octo");
    when(handleDbRequests.generatePasswordResetToken(OCTOPUS))
        .thenReturn(ApiResultStatus.FAILURE.value);

    ResetPasswordInfo resetInfo = usersTeamsControllerService.resetPasswordGenerateToken(OCTOPUS);
    assertThat(resetInfo.isUserFound()).isEqualTo(true);
    assertThat(resetInfo.isTokenSent()).isEqualTo(false);
  }

  @Test
  public void getTeamDetails() {
    Team teamDaoMock = utilMethods.getTeamDaoMock();
    Map<Integer, String> tenantMapMock = utilMethods.getTenantMapMock();

    getTeamDetailsSetupTest(tenantMapMock, teamDaoMock, "testUserName");

    TeamModelResponse response =
        usersTeamsControllerService.getTeamDetails(TEST_TEAM_ID, TEST_TENANT_NAME);

    getTeamDetailsVerifyResponse(response, teamDaoMock, tenantMapMock);
    assertThat(response.getEnvList())
        .isEqualTo(List.of(teamDaoMock.getRequestTopicsEnvs().split("\\s*,\\s*")));
  }

  @Test
  public void getTeamDetailsNoRequestTopicsEnvs() {
    Team teamDaoMock = utilMethods.getTeamDaoMock();
    teamDaoMock.setRequestTopicsEnvs(null);
    Map<Integer, String> tenantMapMock = utilMethods.getTenantMapMock();

    getTeamDetailsSetupTest(tenantMapMock, teamDaoMock, "testUserName");

    TeamModelResponse response =
        usersTeamsControllerService.getTeamDetails(TEST_TEAM_ID, TEST_TENANT_NAME);

    getTeamDetailsVerifyResponse(response, teamDaoMock, tenantMapMock);
    assertThat(response.getEnvList()).isNull();
  }

  @Test
  public void getTeamDetailsTeamDoesNotExist() {
    final String testUserName = "testUserName";
    when(mailService.getUserName(any())).thenReturn(testUserName);
    when(commonUtilsService.getTenantId(anyString())).thenReturn(TEST_TENANT_ID);
    when(handleDbRequests.getTeamDetails(TEST_TEAM_ID, TEST_TENANT_ID)).thenReturn(null);

    TeamModelResponse response =
        usersTeamsControllerService.getTeamDetails(TEST_TEAM_ID, TEST_TENANT_NAME);

    assertThat(response).isNull();
  }

  @Test
  public void getTeamDetailsInvalidTenantName() {
    Team teamDaoMock = utilMethods.getTeamDaoMock();

    getTeamDetailsSetupTest(Collections.emptyMap(), teamDaoMock, "testUserName");

    assertThatExceptionOfType(NoSuchElementException.class)
        .isThrownBy(
            () -> usersTeamsControllerService.getTeamDetails(TEST_TEAM_ID, TEST_TENANT_NAME))
        .withMessage("No value present");
  }

  @Test
  public void getAllTeamsSUFromRegisterUsers() {
    Team team = utilMethods.getTeamDaoMock();
    List<Env> envs = utilMethods.getEnvLists();
    Map<Integer, String> tenantMap = utilMethods.getTenantMapMock();

    getAllTeamsSUFromRegisteredUsersSetupTest(List.of(team), envs, tenantMap);

    List<TeamModelResponse> teamModelResponses =
        usersTeamsControllerService.getAllTeamsSUFromRegisterUsers();

    assertThat(teamModelResponses.size()).isEqualTo(1);
    TeamModelResponse teamModelResponse = teamModelResponses.get(0);

    getAllTeamsSUFromRegisteredUsersVerifyResponse(teamModelResponse, team, envs);
    verify(manageDatabase, times(3)).getKafkaEnvList(TEST_TENANT_ID);
  }

  @Test
  public void getAllTeamsSUFromRegisterUsersNoEnvs() {
    Team team = utilMethods.getTeamDaoMock();
    team.setRequestTopicsEnvs(null);

    List<Env> envs = utilMethods.getEnvLists();
    Map<Integer, String> tenantMap = utilMethods.getTenantMapMock();

    getAllTeamsSUFromRegisteredUsersSetupTest(List.of(team), envs, tenantMap);

    List<TeamModelResponse> teamModelResponses =
        usersTeamsControllerService.getAllTeamsSUFromRegisterUsers();

    assertThat(teamModelResponses.size()).isEqualTo(1);
    TeamModelResponse teamModelResponse = teamModelResponses.get(0);

    getAllTeamsSUFromRegisteredUsersVerifyResponse(teamModelResponse, team, null);
    verify(manageDatabase, never()).getKafkaEnvList(anyInt());
  }

  @Test
  public void getAllTeamsSUFromRegisterUsersEnvInvalidForTenant() {
    List<Team> teams = utilMethods.getTeamsForTenant();
    teams.get(0).setRequestTopicsEnvs("1, X, 3");
    teams.get(1).setRequestTopicsEnvs("X, 1, 2");
    teams.get(2).setRequestTopicsEnvs("1, 2, X");

    List<Env> envs = utilMethods.getEnvLists();
    Map<Integer, String> tenantMap = utilMethods.getTenantMapMock();

    getAllTeamsSUFromRegisteredUsersSetupTest(teams, envs, tenantMap);

    List<TeamModelResponse> teamModelResponses =
        usersTeamsControllerService.getAllTeamsSUFromRegisterUsers();

    assertThat(teamModelResponses.size()).isEqualTo(3);

    getAllTeamsSUFromRegisteredUsersVerifyResponse(
        teamModelResponses.get(0), teams.get(0), List.of(envs.get(0)));
    getAllTeamsSUFromRegisteredUsersVerifyResponse(
        teamModelResponses.get(1), teams.get(1), Collections.emptyList());
    getAllTeamsSUFromRegisteredUsersVerifyResponse(
        teamModelResponses.get(2), teams.get(2), List.of(envs.get(0), envs.get(1)));

    verify(manageDatabase, times(6)).getKafkaEnvList(TEST_TENANT_ID);
  }

  @Test
  public void getAllTeamsSUFromRegisterUsersNoUsersForTenant() {
    getAllTeamsSUFromRegisteredUsersSetupTest(
        Collections.emptyList(), utilMethods.getEnvLists(), utilMethods.getTenantMapMock());

    List<TeamModelResponse> teamModelResponses =
        usersTeamsControllerService.getAllTeamsSUFromRegisterUsers();

    assertThat(teamModelResponses.size()).isEqualTo(0);
    verify(manageDatabase, never()).getKafkaEnvList(anyInt());
  }

  @Test
  public void getAllTeamsSUOnlyWhenNoMatchingTeamName() {
    Map<Integer, String> tenantMap = utilMethods.getTenantMapMock();
    List<Team> teamsForTenant = utilMethods.getTeamsForTenant();
    List<Team> teamsForUser = List.of(utilMethods.getTeamDaoMock());
    teamsForUser.get(0).setTeamname("diffName");
    List<UserInfo> userInfoList = utilMethods.getUserInfoList(1, "testUser");

    getAllTeamsSUSetupTest(teamsForTenant, userInfoList, tenantMap, false);
    when(handleDbRequests.getAllTeamsOfUsers(TEST_AUTHENTICATED_USER_UNAME, TEST_TENANT_ID))
        .thenReturn(teamsForUser);

    List<String> resultTeamNames = usersTeamsControllerService.getAllTeamsSUOnly();

    assertThat(resultTeamNames.size()).isEqualTo(teamsForTenant.size() + teamsForUser.size() + 1);
    assertThat(resultTeamNames.get(0)).isEqualTo("All teams");
    assertThat(resultTeamNames.get(1)).isEqualTo(teamsForUser.get(0).getTeamname());
    for (int i = 0; i < teamsForTenant.size(); i++) {
      assertThat(resultTeamNames.get(i + 2)).isEqualTo(teamsForTenant.get(i).getTeamname());
    }
  }

  @Test
  public void getAllTeamsSUOnlyWhenMatchingTeamName() {
    Map<Integer, String> tenantMap = utilMethods.getTenantMapMock();
    List<Team> teamsForTenant = utilMethods.getTeamsForTenant();
    List<Team> teamsForUser = List.of(utilMethods.getTeamDaoMock());
    List<UserInfo> userInfoList = utilMethods.getUserInfoList(1, "testUser");

    getAllTeamsSUSetupTest(teamsForTenant, userInfoList, tenantMap, false);
    when(handleDbRequests.getAllTeamsOfUsers(TEST_AUTHENTICATED_USER_UNAME, TEST_TENANT_ID))
        .thenReturn(teamsForUser);

    List<String> resultTeamNames = usersTeamsControllerService.getAllTeamsSUOnly();

    assertThat(resultTeamNames.size()).isEqualTo(teamsForTenant.size() + teamsForUser.size());
    assertThat(resultTeamNames.get(0)).isEqualTo("All teams");
    for (int i = 0; i < teamsForTenant.size(); i++) {
      assertThat(resultTeamNames.get(i + 1)).isEqualTo(teamsForTenant.get(i).getTeamname());
    }
  }

  @Test
  public void getAllTeamsSUMultipleTeams() {
    Map<Integer, String> tenantMap = utilMethods.getTenantMapMock();
    List<Team> teamList = utilMethods.getTeamsForTenant();
    List<UserInfo> userInfoList = utilMethods.getUserInfoList(1, "testUser");
    userInfoList.get(0).setSwitchAllowedTeamIds(Set.of(Integer.MAX_VALUE));

    getAllTeamsSUSetupTest(teamList, userInfoList, tenantMap, false);

    for (Team team : teamList) {
      when(handleDbRequests.existsComponentsCountForTeam(team.getTeamId(), TEST_TENANT_ID))
          .thenReturn(false);
      when(handleDbRequests.existsUsersInfoForTeam(team.getTeamId(), TEST_TENANT_ID))
          .thenReturn(false);
    }

    List<TeamModelResponse> teamModelResponses = usersTeamsControllerService.getAllTeamsSU();

    assertThat(teamModelResponses.size()).isEqualTo(teamList.size());
    getAllTeamSUVerifyResponse(teamModelResponses, teamList, tenantMap);

    for (TeamModelResponse teamModelResponse : teamModelResponses) {
      assertThat(teamModelResponse.isShowDeleteTeam()).isTrue();
    }

    verify(handleDbRequests, times(3)).existsComponentsCountForTeam(anyInt(), anyInt());
    verify(handleDbRequests, times(3)).existsUsersInfoForTeam(anyInt(), anyInt());
  }

  @Test
  public void getAllTeamsSUNoTeams() {
    Map<Integer, String> tenantMap = utilMethods.getTenantMapMock();
    List<UserInfo> userInfoList = utilMethods.getUserInfoList(1, "testUser");

    getAllTeamsSUSetupTest(Collections.emptyList(), userInfoList, tenantMap, false);

    List<TeamModelResponse> teamModelResponses = usersTeamsControllerService.getAllTeamsSU();

    assertThat(teamModelResponses).isEmpty();
    verify(handleDbRequests, never()).existsComponentsCountForTeam(anyInt(), anyInt());
    verify(handleDbRequests, never()).existsUsersInfoForTeam(anyInt(), anyInt());
  }

  @ParameterizedTest
  @MethodSource
  public void getAllTeamsSUShowDeleteTeam(
      boolean existComponentsCountForTeam,
      boolean existUsersInfoForTeam,
      boolean switchAllowedTeamMatch,
      boolean unAuthorizedUser) {
    Map<Integer, String> tenantMap = utilMethods.getTenantMapMock();
    List<Team> teamList = utilMethods.getTeams();
    teamList.get(0).setTeamId(TEST_TEAM_ID);

    List<UserInfo> userInfoList = utilMethods.getUserInfoList(1, "testUser");
    if (switchAllowedTeamMatch) {
      userInfoList.get(0).setSwitchAllowedTeamIds(Set.of(TEST_TEAM_ID));
    } else {
      userInfoList.get(0).setSwitchAllowedTeamIds(Set.of(TEST_TEAM_ID + 1));
    }

    getAllTeamsSUSetupTest(teamList, userInfoList, tenantMap, unAuthorizedUser);
    when(handleDbRequests.existsComponentsCountForTeam(TEST_TEAM_ID, TEST_TENANT_ID))
        .thenReturn(existComponentsCountForTeam);
    when(handleDbRequests.existsUsersInfoForTeam(TEST_TEAM_ID, TEST_TENANT_ID))
        .thenReturn(existUsersInfoForTeam);

    List<TeamModelResponse> teamModelResponses = usersTeamsControllerService.getAllTeamsSU();

    assertThat(teamModelResponses.size()).isEqualTo(1);
    getAllTeamSUVerifyResponse(teamModelResponses, teamList, tenantMap);

    if (!unAuthorizedUser) {
      if (existComponentsCountForTeam || existUsersInfoForTeam || switchAllowedTeamMatch) {
        assertThat(teamModelResponses.get(0).isShowDeleteTeam()).isFalse();
      } else {
        assertThat(teamModelResponses.get(0).isShowDeleteTeam()).isTrue();
      }
    } else {
      assertThat(teamModelResponses.get(0).isShowDeleteTeam()).isFalse();
      verify(handleDbRequests, never()).existsComponentsCountForTeam(anyInt(), anyInt());
      verify(handleDbRequests, never()).existsUsersInfoForTeam(anyInt(), anyInt());
    }
  }

  public static Stream<Arguments> getAllTeamsSUShowDeleteTeam() {
    return Stream.of(
        Arguments.of(false, false, false, false),
        Arguments.of(true, false, false, false),
        Arguments.of(false, true, false, false),
        Arguments.of(false, false, true, false),
        Arguments.of(false, false, false, true));
  }

  @Test
  public void deleteTeamSuccess() throws KlawException {
    deleteTeamSetup(ApiResultStatus.SUCCESS, false, false, false, false, TEST_TEAM_ID + 1);

    ApiResponse apiResponse = usersTeamsControllerService.deleteTeam(TEST_TEAM_ID);

    assertThat(apiResponse.isSuccess()).isTrue();
    assertThat(apiResponse.getMessage()).isEqualTo(ApiResponse.SUCCESS.getMessage());
    verify(commonUtilsService)
        .updateMetadata(TEST_TENANT_ID, EntityType.TEAM, MetadataOperationType.DELETE, null);
  }

  @Test
  public void deleteTeamFailureUnAuthorizedUser() throws KlawException {
    deleteTeamSetup(null, true, false, false, false, Integer.MAX_VALUE);

    ApiResponse apiResponse = usersTeamsControllerService.deleteTeam(TEST_TEAM_ID);

    assertThat(apiResponse.isSuccess()).isFalse();
    assertThat(apiResponse.getMessage()).isEqualTo(ApiResponse.NOT_AUTHORIZED.getMessage());
    verifyNoInteractions(manageDatabase);
    verifyNoInteractions(handleDbRequests);
    verify(commonUtilsService, never()).getTenantId(anyString());
    verify(commonUtilsService, never()).updateMetadata(anyInt(), any(), any(), anyString());
  }

  @Test
  public void deleteTeamFailureUserInfoForTeamExists() throws KlawException {
    deleteTeamSetup(null, false, true, false, false, TEST_TEAM_ID);

    ApiResponse apiResponse = usersTeamsControllerService.deleteTeam(TEST_TEAM_ID);

    assertThat(apiResponse.isSuccess()).isFalse();
    assertThat(apiResponse.getMessage()).isEqualTo(KlawErrorMessages.TEAMS_ERR_103);
    verify(handleDbRequests, never()).existsComponentsCountForTeam(anyInt(), anyInt());
    verify(handleDbRequests, never()).deleteTeamRequest(anyInt(), anyInt());
    verify(commonUtilsService, never()).updateMetadata(anyInt(), any(), any(), anyString());
  }

  @Test
  public void deleteTeamFailureComponentCountForTeamExists() throws KlawException {
    deleteTeamSetup(null, false, false, true, false, TEST_TEAM_ID);

    ApiResponse apiResponse = usersTeamsControllerService.deleteTeam(TEST_TEAM_ID);

    assertThat(apiResponse.isSuccess()).isFalse();
    assertThat(apiResponse.getMessage()).isEqualTo(KlawErrorMessages.TEAMS_ERR_104);
    verify(handleDbRequests, never()).deleteTeamRequest(anyInt(), anyInt());
    verify(commonUtilsService, never()).updateMetadata(anyInt(), any(), any(), anyString());
  }

  @Test
  public void deleteTeamFailureDeletingOwnTeam() throws KlawException {
    deleteTeamSetup(null, false, false, false, false, TEST_TEAM_ID);

    ApiResponse apiResponse = usersTeamsControllerService.deleteTeam(TEST_TEAM_ID);

    assertThat(apiResponse.isSuccess()).isFalse();
    assertThat(apiResponse.getMessage()).isEqualTo(KlawErrorMessages.TEAMS_ERR_105);
    verify(handleDbRequests, never()).deleteTeamRequest(anyInt(), anyInt());
    verify(commonUtilsService, never()).updateMetadata(anyInt(), any(), any(), anyString());
  }

  @Test
  public void deleteTeamFailureDbApi() throws KlawException {
    deleteTeamSetup(ApiResultStatus.FAILURE, false, false, false, false, TEST_TEAM_ID + 1);

    ApiResponse apiResponse = usersTeamsControllerService.deleteTeam(TEST_TEAM_ID);

    assertThat(apiResponse.isSuccess()).isFalse();
    assertThat(apiResponse.getMessage()).isEqualTo(ApiResultStatus.FAILURE.value);
    verify(commonUtilsService, never()).updateMetadata(anyInt(), any(), any(), anyString());
  }

  @Test
  public void deleteTeamFailureDbException() {
    deleteTeamSetup(null, false, false, false, true, TEST_TEAM_ID + 1);

    assertThatExceptionOfType(KlawException.class)
        .isThrownBy(() -> usersTeamsControllerService.deleteTeam(TEST_TEAM_ID))
        .withMessage("Db exception");

    verify(commonUtilsService, never()).updateMetadata(anyInt(), any(), any(), anyString());
  }

  @Test
  public void deleteUserFailureHasRequests() throws KlawException {
    String userName = "testuser";
    when(commonUtilsService.isNotAuthorizedUser(userDetails, PermissionType.ADD_EDIT_DELETE_USERS))
        .thenReturn(false);
    when(handleDbRequests.getUsersInfo(anyString())).thenReturn(userInfo);
    when(commonUtilsService.getTenantId(anyString())).thenReturn(TEST_TENANT_ID);
    when(mailService.getUserName(userDetails)).thenReturn(userName);
    when(manageDatabase.getRolesPermissionsPerTenant(anyInt())).thenReturn(new HashMap<>());
    when(handleDbRequests.existsComponentsCountForUser("testuser", TEST_TENANT_ID))
        .thenReturn(true);
    ApiResponse apiResponse = usersTeamsControllerService.deleteUser("testuser", false);
    assertThat(apiResponse.getMessage())
        .isEqualTo(
            "Not allowed to delete this user, as there are associated requests in the metadata.");
  }

  @Test
  public void deleteUserFailureisAdmin() throws KlawException {
    when(commonUtilsService.isNotAuthorizedUser(userDetails, PermissionType.ADD_EDIT_DELETE_USERS))
        .thenReturn(false);
