package org.gcube.keycloak.avatar;

import java.io.InputStream;

import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;

import org.apache.commons.io.IOUtils;
import org.gcube.keycloak.avatar.storage.AvatarStorageProvider;
import org.gcube.keycloak.avatar.storage.file.FileAvatarStorageProvider;
import org.jboss.logging.Logger;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.AuthenticationManager.AuthResult;

public abstract class AbstractAvatarResource {

    protected static final Logger logger = Logger.getLogger(AbstractAvatarResource.class);

    protected static final String AVATAR_IMAGE_PARAMETER = "image";

    public static final Class<?> DEFAULT_IMPLEMENTATION = FileAvatarStorageProvider.class;

    protected KeycloakSession session;
    protected AuthenticationManager.AuthResult auth;

    public AbstractAvatarResource(KeycloakSession session) {
        this.session = session;
        auth = authenticate(session);
    }

    private AuthResult authenticate(KeycloakSession session) {
        logger.debug("Authenticating with bearer token");
        AuthResult auth = this.auth = new AppAuthManager.BearerTokenAuthenticator(session).authenticate();

        if (auth == null) {
            logger.debug("Authenticating with identity cookie");
            auth = new AppAuthManager().authenticateIdentityCookie(session, session.getContext().getRealm());
        }
        return auth;
    }

    public AvatarStorageProvider getAvatarStorageProvider() {
        AvatarStorageProvider asp = lookupAvatarStorageProvider(session);
        if (asp == null) {
            logger.warnf("Provider not found via SPI configuration, defaulting to: %s",
                    DEFAULT_IMPLEMENTATION.getName());

            try {
                asp = (AvatarStorageProvider) DEFAULT_IMPLEMENTATION.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                logger.error("Cannot instatiate storage implementation class", e);
            }
        }
        return asp;
    }

    protected AvatarStorageProvider lookupAvatarStorageProvider(KeycloakSession keycloakSession) {
        return keycloakSession.getProvider(AvatarStorageProvider.class);
    }

    protected void saveUserImage(RealmModel realm, UserModel user, InputStream imageInputStream) {
        getAvatarStorageProvider().saveAvatarImage(realm, user, imageInputStream);
    }

    protected StreamingOutput fetchUserImage(RealmModel realm, UserModel user) {
        AvatarStorageProvider asp = getAvatarStorageProvider();
        InputStream is = asp.loadAvatarImage(realm, user);
        return is != null ? output -> IOUtils.copy(is, output) : null;
    }


    protected Response fetchAndCreateResponse(RealmModel realm, UserModel user) {
        StreamingOutput so = fetchUserImage(realm, user);
        if (so == null) {
            throw new NotFoundException("Avatar image not found");
        }
        return Response.ok(so).build();
    }

}
