package de.jottyfan.camporganizer.module.registration;

import java.util.Arrays;
import java.util.Collections;

import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.KeycloakBuilder;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

/**
 *
 * @author henkej
 *
 */
@Repository
public class KeycloakRepository {
	private final static Logger LOGGER = LogManager.getLogger(KeycloakRepository.class);

	@Value("${keycloak.client-id}")
	private String keycloakClientId;

	@Value("${keycloak.auth-server-url}")
	private String keycloakUrl;

	@Value("${keycloak.realm}")
	private String keycloakRealm;

	@Value("${ow.keycloak.admin.name}")
	private String keycloakAdminName;

	@Value("${ow.keycloak.admin.password}")
	private String keycloakAdminPassword;

	/**
	 * get the url of the user client
	 *
	 * @return the url of the user client
	 */
	public String getUserClientUrl() {
		String url = keycloakUrl == null ? null
				: (keycloakUrl.substring(0, keycloakUrl.length() - (keycloakUrl.endsWith("/") ? 1 : 0)));
		return String.format("%s/realms/%s/account/", url, keycloakRealm);
	}

	/**
	 * get the url of the user password client
	 *
	 * @return the url of the user password client
	 */
	public String getPasswordClientUrl() {
		return String.format("%s%s", getUserClientUrl(), "#/security/signingin");
	}

	/**
	 * register the login in keycloak
	 *
	 * @param forename the forename
	 * @param surname  the surname
	 * @param login    the username
	 * @param password the password
	 * @param email    the email
	 * @return true or false
	 */
	public boolean register(String forename, String surname, String login, String password, String email) {
		UserRepresentation user = getUserRepresentation(forename, surname, login, password, email);
		UsersResource resource = getUsersResource(keycloakUrl, keycloakRealm, keycloakAdminName, keycloakAdminPassword,
				keycloakClientId);
		return register(resource, user);
	}

	/**
	 * generate a user representation
	 *
	 * @param forename the forename
	 * @param surname  the surname
	 * @param login    the login
	 * @param password the password
	 * @param email    the email
	 * @return the user representation
	 */
	protected UserRepresentation getUserRepresentation(String forename, String surname, String login, String password,
			String email) {
		CredentialRepresentation passwordCredentials = new CredentialRepresentation();
		passwordCredentials.setTemporary(false);
		passwordCredentials.setType(CredentialRepresentation.PASSWORD);
		passwordCredentials.setValue(password);

		UserRepresentation user = new UserRepresentation();
		user.setUsername(login);
		user.setFirstName(forename);
		user.setLastName(surname);
		user.setEmail(email);
		user.setCredentials(Collections.singletonList(passwordCredentials));
		user.setRequiredActions(Arrays.asList(UserModel.RequiredAction.VERIFY_EMAIL.toString()));
		user.setEnabled(true);

		return user;
	}

	/**
	 * register a user in keycloak
	 *
	 * @param resource the resource
	 * @param user     the user
	 * @return true or false
	 */
	protected boolean register(UsersResource resource, UserRepresentation user) {
		Response response = resource.create(user);
		Boolean success = Status.CREATED.equals(response.getStatusInfo());
		if (success) {
			LOGGER.debug("created new keycloak user {}", user.getUsername());
		} else {
			LOGGER.error("error on creating keycloak user {}: {}", user.getUsername(), response.getStatus());
		}
		return success;
	}

	/**
	 * generate a keycloak object with the special arguments
	 *
	 * @param url      the url
	 * @param realm    the realm
	 * @param admin    the admin of the realm
	 * @param password the password
	 * @param clientId the client ID
	 * @return the keycloak object
	 */
	public KeycloakBuilder getKeycloak(String url, String realm, String admin, String password, String clientId) {
		return KeycloakBuilder.builder().serverUrl(url).realm(realm).grantType(OAuth2Constants.PASSWORD).username(admin)
				.password(password).clientId(clientId)
				.resteasyClient(new ResteasyClientBuilderImpl().connectionPoolSize(10).build());
	}

	/**
	 * generate a users resource object
	 *
	 * @param url      the url
	 * @param realm    the realm
	 * @param admin    the admin of the realm
	 * @param password the password
	 * @param clientId the client ID
	 * @return the users resource
	 */
	public UsersResource getUsersResource(String url, String realm, String admin, String password, String clientId) {
		return getKeycloak(url, realm, admin, password, clientId).build().realm(realm).users();
	}

}
