package ru.micord.ervu.account_applications.security.provider;

import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import ru.micord.ervu.account_applications.security.model.jwt.UserClaims;
import ru.micord.ervu.account_applications.security.model.UserSession;
import ru.micord.ervu.account_applications.security.model.jwt.authentication.JwtTokenAuthentication;
import ru.micord.ervu.account_applications.security.model.jwt.authentication.JwtTokenDummy;
import ru.micord.ervu.account_applications.security.model.role.ErvuPermissionAuthority;
import ru.micord.ervu.account_applications.security.service.JwtTokenService;

@Component
public class ErvuJwtAuthenticationProvider implements AuthenticationProvider {

  private final JwtTokenService jwtTokenService;

  public ErvuJwtAuthenticationProvider(JwtTokenService jwtTokenService) {
    this.jwtTokenService = jwtTokenService;
  }

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    JwtTokenDummy jwtTokenDummy = (JwtTokenDummy) authentication;
    String jwtToken = jwtTokenDummy.getToken();
    String permissionHeader = jwtTokenDummy.getPermissionsHeader();
    UserClaims userClaims = jwtTokenService.getUserClaims(jwtToken);
    Set<ErvuPermissionAuthority> permissions = extractPermissionsFromHeader(permissionHeader);
    UserSession userSession = UserSession.builder()
        .withDomainId(userClaims.domainId())
        .withUserId(userClaims.userId())
        .withPermissions(permissions)
        .withName(userClaims.name())
        .withRealm(userClaims.realm())
        .build();
    return new JwtTokenAuthentication(userSession, jwtToken);
  }

  private Set<ErvuPermissionAuthority> extractPermissionsFromHeader(String permissionsHeader) {
    if (!StringUtils.hasText(permissionsHeader)) {
      return Collections.emptySet();
    }

    return Arrays.stream(permissionsHeader.split(","))
        .map(String::trim)
        .filter(StringUtils::hasText)
        .map(String::toLowerCase)
        .map(ErvuPermissionAuthority::new)
        .collect(Collectors.toSet());
  }

  @Override
  public boolean supports(Class<?> authentication) {
    return JwtTokenDummy.class.isAssignableFrom(authentication);
  }
}
