package org.egl_cepgl.pm.service;

import lombok.extern.slf4j.Slf4j;
import org.egl_cepgl.pm.dto.*;
import org.egl_cepgl.pm.exception.ErrorCodes;
import org.egl_cepgl.pm.exception.InvalidEntityException;
import org.egl_cepgl.pm.model.user.User;
import org.egl_cepgl.pm.service.keycloak.KeycloakUserService;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.*;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import org.keycloak.authorization.client.AuthzClient;

import jakarta.ws.rs.core.Response;
import java.util.*;

@Service
@Slf4j
public class KeyCloakUserServiceImpl implements KeycloakUserService
{
    @Value("${keycloak.realm2}")
    private String REALM;

    @Value("${keycloak.client}")
    private String KC_CLIENT;

    private final Keycloak keyCloakAdminClient;

    @Autowired
    public KeyCloakUserServiceImpl(Keycloak keyCloakAdminClient) {
        this.keyCloakAdminClient = keyCloakAdminClient;
    }

    @Override
    public String createUser(UserRegistrationDto userRegistrationRecord) throws Exception {
        UserRepresentation user=new UserRepresentation();
        user.setEnabled(true);
        user.setUsername(userRegistrationRecord.username());
        user.setEmail(userRegistrationRecord.email());
        user.setFirstName(userRegistrationRecord.firstName());
        user.setLastName(userRegistrationRecord.lastName());
        user.setEmailVerified(true);

        CredentialRepresentation credentialRepresentation=new CredentialRepresentation();
        credentialRepresentation.setValue(userRegistrationRecord.password());
        credentialRepresentation.setTemporary(false);
        credentialRepresentation.setType(CredentialRepresentation.PASSWORD);

        List<CredentialRepresentation> list = new ArrayList<>();
        list.add(credentialRepresentation);
        user.setCredentials(list);
        UsersResource usersResource = getUsersResource();
        List<UserRepresentation> representationList = usersResource.searchByUsername(userRegistrationRecord.username(), true);
        if(CollectionUtils.isEmpty(representationList))
        {
            try (Response response = usersResource.create(user)) {
                if (response.getStatus() == 201) {
                    List<UserRepresentation> representationListNew = usersResource.searchByUsername(userRegistrationRecord.username(), true);
                    if(!CollectionUtils.isEmpty(representationListNew)){
                        UserResource userResource = this.getUserResource(representationListNew.get(0).getId());
                        
                        List<ClientRepresentation> clientList = getClientsResource().findByClientId(KC_CLIENT);
                        
                        if (CollectionUtils.isEmpty(clientList)) {
                            System.err.println("ERREUR CRITIQUE : Le client '" + KC_CLIENT + "' est introuvable dans ce Realm Keycloak !");
                            return representationListNew.get(0).getId(); // On retourne quand même l'ID pour éviter de crasher l'appli
                        }
                        
                        ClientRepresentation app1Client = clientList.get(0);
                        
                        List<RoleRepresentation> availableRoles = getClientsResource().get(app1Client.getId()).roles().list();
                        RoleRepresentation userClientRole = availableRoles.stream()
                            .filter(role -> "ADMIN".equalsIgnoreCase(role.getName()))
                            .findFirst()
                            .orElse(null);
                
                        if (userClientRole == null) {
                            System.err.println("ERREUR : Le rôle 'ADMIN' n'existe pas encore pour le client " + KC_CLIENT);
                        } else {
                            userResource.roles().clientLevel(app1Client.getId()).add(Collections.singletonList(userClientRole));
                        }
                
                        return representationListNew.get(0).getId();
                    }
                }else {
                    System.out.println("Failed to create user: " + response.getStatusInfo().getReasonPhrase());
                }
            }
        }else if(Objects.equals(409,usersResource.create(user).getStatus())){
            throw new InvalidEntityException("Username/Email already exists", ErrorCodes.USERNAME_ALREADY);
        }
        return null;
    }

    @Override
    public void updateUser(UserUpdateDto user)
    {
        if(user.getIdkcloak() != null){
            UserRepresentation userP = getUserById(user.getIdkcloak());
            userP.setFirstName(user.getFirstname());
            userP.setLastName(user.getLastname());
            userP.setEmail(user.getEmail());
            getUsersResource().get(user.getIdkcloak()).update(userP);
        }
    }

    private UsersResource getUsersResource() {
        RealmResource realm1 = keyCloakAdminClient.realm(REALM);
        return realm1.users();
    }

    private ClientsResource getClientsResource() {
        RealmResource realm1 = keyCloakAdminClient.realm(REALM);
        return realm1.clients();
    }

    @Override
    public UserRepresentation getUserById(String userId)
    {
        return getUsersResource().get(userId).toRepresentation();
    }

    @Override
    public ClientRepresentation getClientById(String clientId)
    {
        return getClientsResource().get(clientId).toRepresentation();
    }

    @Override
    public void changeUserStatus(User obj)
    {
        if(obj.getIdkcloak() != null){
            UserRepresentation user = getUserById(obj.getIdkcloak());
            user.setEnabled(obj.getStatus());
            getUsersResource().get(obj.getIdkcloak()).update(user);
        }
    }

    @Override
    public void changeUserAdmin(User obj)
    {
        if(obj.getIdkcloak() != null)
        {
            UserResource userResource = this.getUserResource(obj.getIdkcloak());
            ClientRepresentation app1Client = getClientsResource().findByClientId(KC_CLIENT).get(0);
            RoleRepresentation userClientRole = getClientsResource().get(app1Client.getId()).roles().get("ADMIN").toRepresentation();

            assert userClientRole != null;
            if(obj.getIs_admin()){
                userResource.roles().clientLevel(app1Client.getId()).add(Collections.singletonList(userClientRole));
            }else{
                userResource.roles().clientLevel(app1Client.getId()).remove(Collections.singletonList(userClientRole));
            }
        }
    }

    @Override
    public void deleteUserById(String userId)
    {
        getUsersResource().delete(userId);
    }

    @Override
    public void emailVerification(String userId)
    {
        UsersResource usersResource = getUsersResource();
        usersResource.get(userId).sendVerifyEmail();
    }

    public UserResource getUserResource(String userId){
        UsersResource usersResource = getUsersResource();
        return usersResource.get(userId);
    }

    @Override
    public void updatePassword(String userId) {
        UserResource userResource = getUserResource(userId);
        List<String> actions= new ArrayList<>();
        actions.add("UPDATE_PASSWORD");
        userResource.executeActionsEmail(actions);
    }

    @Override
    public String changeUserPassword(CheckPwdByKcl obj)
    {
        UserResource userResource = getUserResource(obj.getIdkcloak());
        CredentialRepresentation credentialRepresentation=new CredentialRepresentation();
        credentialRepresentation.setValue(obj.getPassword());
        credentialRepresentation.setType(CredentialRepresentation.PASSWORD);
        credentialRepresentation.setTemporary(false);
        userResource.resetPassword(credentialRepresentation);
        if(this.checkPasswordByKcl(obj)){
            return obj.getIdkcloak();
        }
        return null;
    }

    @Override
    public Boolean checkPasswordByKcl(CheckPwdByKcl obj)
    {
        UserRepresentation user = getUserById(obj.getIdkcloak());
        String username= user.getUsername();
        AuthzClient authzClient = AuthzClient.create();
        AccessTokenResponse response =  authzClient.obtainAccessToken(username, obj.getPassword());
        if (response.getToken() != null && !response.getToken().isEmpty()) {
            return true;
        }
        return false;
    }

    public String getCurrentUsername(){
        String username= null;
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth.getPrincipal() instanceof KeycloakPrincipal) {
            KeycloakPrincipal<?> keycloakPrincipal = (KeycloakPrincipal<?>) auth.getPrincipal();
            username = keycloakPrincipal.getName();
        }
        return username;
    }
}

//@Slf4j
//@Service
//public class KeyCloakUserService
//{
//    @Value("${keycloak.realm}")
//    private String realm;
//
//    private Keycloak keycloak;
//    private final RoleService roleService;
//    private UserService userService;
//    private UserRepository userRepository;
//
//    public KeyCloakUserService(Keycloak keycloak, RoleService roleService, UserService userService, UserRepository userRepository)
//    {
//        this.keycloak = keycloak;
//        this.roleService = roleService;
//        this.userService= userService;
//        this.userRepository= userRepository;
//    }
//
//    public KCUserRegister addUser(KCUserRegister ur)
//    {
//        User userd= new User("", ur.getFull_name(), ur.getEmail(), ur.getPassword(),ur.getPhone(), false);
////        SignInValidator signInValidator= new SignInValidator(userRepository);
////        Map<String, List<String>> errors= signInValidator.validate(UserDto.fromEntity(userd));
////        if(!errors.isEmpty())
////            throw new InvalidEntityException("Invalid==", ErrorCodes.USER_NOT_VALID, errors);
//
//        UserRepresentation user=new UserRepresentation();
//        user.setEnabled(true);
//        user.setUsername(ur.getEmail());
//        user.setEmail(ur.getEmail());
//        user.setFirstName(ur.getFull_name());
//        user.setEmailVerified(false);
//
//        CredentialRepresentation credentialRepresentation=new CredentialRepresentation();
//        credentialRepresentation.setValue(ur.getPassword());
//        credentialRepresentation.setTemporary(false);
//        credentialRepresentation.setType(CredentialRepresentation.PASSWORD);
//        List<CredentialRepresentation> list = new ArrayList<>();
//        list.add(credentialRepresentation);
//        user.setCredentials(list);
//        UsersResource usersResource = getUsersResource();
//        Response response = usersResource.create(user);
//        if(Objects.equals(201,response.getStatus()) || Objects.equals(200,response.getStatus()))
//        {
//            List<UserRepresentation> rpl = usersResource.searchByUsername(ur.getUsername(), true);
//            if(!CollectionUtils.isEmpty(rpl))
//            {
//                UserRepresentation up1 = rpl.stream().filter(up ->
//                        Objects.equals(false, up.isEmailVerified())).findFirst().orElse(null);
//                //if (ur.isAdmin())
//                //this.roleService.assignRole(up1.getId(), "admin");
//                //assert up1 != null;
//                //emailVerification(userRepresentation1.getId());
//                log.info("BVDDD==="+userd.toString()+"===="+up1.toString());
//                userd.setId_kcloak(up1.getId());
//                //if(!errors.isEmpty())
//                this.userService.addUser(UserDto.fromEntity(userd));
//            }
//            return ur;
//        }
//        return null;
//    }
//
//    private UsersResource getUsersResource() {
//        RealmResource realm1 = keycloak.realm(realm);
//        return realm1.users();
//    }
//
//    public void emailVerification(String userId)
//    {
//        UsersResource usersResource = getUsersResource();
//        usersResource.get(userId).sendVerifyEmail();
//    }
//
//    public UserResource getUserResource(String userId)
//    {
//        UsersResource usersResource = getUsersResource();
//        return usersResource.get(userId);
//    }
//}
