package com.airlock.iam.common.application.authentication;

import com.airlock.iam.common.api.domain.model.authentication.Authentee;
import com.airlock.iam.common.api.domain.model.role.Role;
import com.airlock.iam.common.domain.model.user.PrincipalInfo;
import com.airlock.iam.common.domain.model.user.PrincipalInfoImpl;
import jakarta.ws.rs.core.SecurityContext;
import java.security.Principal;
import java.util.Optional;

public final class IamSecurityContext implements SecurityContext {
   private final SecurityContext wrappedSecurityContext;
   private final IamSecurityContext.IamPrincipal principal;

   public IamSecurityContext(Authentee authentee, SecurityContext wrappedSecurityContext) {
      this.wrappedSecurityContext = wrappedSecurityContext;
      this.principal = new IamSecurityContext.IamPrincipal(authentee);
   }

   public Principal getUserPrincipal() {
      return this.principal;
   }

   public boolean isUserInRole(String role) {
      return this.principal.authentee().hasRole(Role.parseRole(role));
   }

   public boolean isSecure() {
      return this.wrappedSecurityContext.isSecure();
   }

   public String getAuthenticationScheme() {
      return this.wrappedSecurityContext.getAuthenticationScheme();
   }

   public static PrincipalInfo extractPrincipalInfoFromSecurityContext(SecurityContext securityContext) {
      return securityContext.getUserPrincipal() == null
         ? PrincipalInfoImpl.forUnknownIdentity()
         : PrincipalInfoImpl.forAuthenticatedIdentity(extractAuthenteeFromSecurityContext(securityContext).orElseThrow().userIdentity());
   }

   public static Optional<Authentee> extractAuthenteeFromSecurityContext(SecurityContext securityContext) {
      return Optional.ofNullable(securityContext)
         .<Principal>map(SecurityContext::getUserPrincipal)
         .filter(IamSecurityContext.IamPrincipal.class::isInstance)
         .map(IamSecurityContext.IamPrincipal.class::cast)
         .map(IamSecurityContext.IamPrincipal::authentee);
   }

   private record IamPrincipal(Authentee authentee) implements Principal {
      @Override
      public String getName() {
         return this.authentee.userIdentity().id().getValue();
      }
   }
}
