package com.airlock.iam.admin.application.service.permission.provider;

import com.airlock.iam.admin.application.configuration.logviewer.LogViewer;
import com.airlock.iam.admin.application.service.permission.PagePermissions;
import com.airlock.iam.admin.application.service.permission.PagePermissionsProvider;
import com.airlock.iam.admin.application.service.permission.UserDetailPermissions;
import com.airlock.iam.admin.application.service.permission.token.TokenPermissions;
import com.airlock.iam.admin.application.system.AdminappPage;
import com.airlock.iam.admin.domain.model.administrator.permissions.Actions;
import com.airlock.iam.admin.domain.model.user.UserSpecificSettings;
import com.airlock.iam.admin.domain.service.access.AdminappAccessController;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Optional;

public final class UserDetailPermissionsProvider implements PagePermissionsProvider {
   private final AdminappAccessController accessController;
   private final UserSpecificSettings userSpecificSettings;
   private final TokenPermissions tokenPermissions;
   private final Optional<LogViewer> logViewer;

   @Override
   public AdminappPage page() {
      return AdminappPage.USER_DETAIL;
   }

   @Override
   public boolean applicableInRecoveryMode() {
      return false;
   }

   @Override
   public PagePermissions getPagePermissions() {
      boolean accessible = this.accessController.isActionAllowed(Actions.viewUser);
      boolean editable = this.accessController.isActionAllowed(Actions.editUser) && this.userSpecificSettings.isEditable();
      PagePermissions.PagePermissionsBuilder builder = PagePermissions.builder()
         .accessible(accessible)
         .defaultPermission(editable ? PagePermissions.DefaultPermission.WRITE : PagePermissions.DefaultPermission.READ);
      if (accessible) {
         this.addDetailedPermissions(builder, editable);
      }

      return builder.build();
   }

   private void addDetailedPermissions(PagePermissions.PagePermissionsBuilder builder, boolean editable) {
      boolean editTokenAllowed = this.isAllowed(Actions.editToken);
      UserDetailPermissions settings = UserDetailPermissions.builder()
         .editProfile(editable)
         .cancelEditProfile(editable)
         .selectRoles(editable)
         .validity(editable)
         .lockUser(this.isAllowed(Actions.lockUser))
         .lockReason(this.isAllowed(Actions.lockUser))
         .unlockUser(this.isAllowed(Actions.unlockUser))
         .activeAuthMethod(editTokenAllowed)
         .additionalActive(editTokenAllowed)
         .saveActiveAuthMethod(editTokenAllowed)
         .removeActiveAuthMethod(editTokenAllowed)
         .newAuthMethod(editTokenAllowed)
         .addNewAuthMethod(editTokenAllowed)
         .migrateToAuthMethod(editTokenAllowed)
         .migrateToAuthMethodUntil(editTokenAllowed)
         .saveAuthMethodMigration(editTokenAllowed)
         .removeAuthMethodMigration(editTokenAllowed)
         .showUserInLogs(this.isLogviewerAccessible())
         .unlinkAccount(this.isAllowed(Actions.deleteToken) && editable)
         .viewUserLogs(this.isAllowed(Actions.viewUserLogs))
         .editUsername(this.isAllowed(Actions.editUsername) && editable)
         .reloadUser(this.isAllowed(Actions.viewUser))
         .deleteUser(this.isAllowed(Actions.deleteUser) && editable)
         .viewToken(this.isAllowed(Actions.viewToken))
         .viewUser(this.isAllowed(Actions.viewUser))
         .deleteToken(this.isAllowed(Actions.deleteToken) && editable)
         .build();
      builder.pagePermissions(settings);
      this.tokenPermissions.applyTokenPermissions(builder);
   }

   private boolean isAllowed(Actions action) {
      return this.accessController.isActionAllowed(action);
   }

   private boolean isLogviewerAccessible() {
      return this.logViewer.isPresent() && !this.logViewer.get().getLogFiles().isEmpty() && this.isAllowed(Actions.viewLog);
   }

   @SuppressFBWarnings(justification = "generated code")
   public UserDetailPermissionsProvider(
      AdminappAccessController accessController, UserSpecificSettings userSpecificSettings, TokenPermissions tokenPermissions, Optional<LogViewer> logViewer
   ) {
      this.accessController = accessController;
      this.userSpecificSettings = userSpecificSettings;
      this.tokenPermissions = tokenPermissions;
      this.logViewer = logViewer;
   }
}
