package org.gcube.keycloak.avatar.storage.file;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.io.IOUtils;
import org.gcube.keycloak.avatar.storage.AvatarStorageProvider;
import org.jboss.logging.Logger;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;

public class FileAvatarStorageProvider implements AvatarStorageProvider {

    private static final Logger logger = Logger.getLogger(FileAvatarStorageProvider.class);

    private final File avatarFolder;
    private final Boolean useEmailAsFilename;

    public FileAvatarStorageProvider() {
        this(FileAvatarStorageProviderFactory.DEFAULT_AVATAR_FOLDER,
                FileAvatarStorageProviderFactory.USE_EMAIL_AS_FILENAME_DEFAULT);
    }

    public FileAvatarStorageProvider(String avatarFolder, Boolean useEmailAsFilename) {
        this.avatarFolder = new File(avatarFolder);
        this.useEmailAsFilename = useEmailAsFilename;
        if (!this.avatarFolder.exists()) {
            logger.infof("Creating avatar folder: %s", this.avatarFolder.getAbsolutePath());
            this.avatarFolder.mkdir();
        }
    }

    @Override
    public void saveAvatarImage(RealmModel realm, UserModel user, InputStream input) {
        checkRealmFolderExistence(realm.getName());
        File avatarFile = getAvatarFile(realm, user);
        logger.debugf("Saving new avatar file for user %s, file path is: %s", user.getUsername(),
                avatarFile.getAbsolutePath());

        if (!avatarFile.exists()) {
            try {
                avatarFile.createNewFile();
            } catch (IOException e) {
                logger.error("Cannot create new avater file", e);
            }
        }
        try (FileOutputStream fos = new FileOutputStream(avatarFile)) {
            IOUtils.copy(input, fos);
        } catch (IOException e) {
            logger.error("Cannot save avatar stream into file", e);
        }
    }

    private void checkRealmFolderExistence(String realmName) {
        File realmFile = new File(avatarFolder, realmName);
        if (!realmFile.exists()) {
            logger.infof("Creating avatar folder for realm '%s' in %s", realmName, realmFile.getAbsolutePath());
            realmFile.mkdir();
        }
    }

    @Override
    public InputStream loadAvatarImage(RealmModel realm, UserModel user) {
        checkRealmFolderExistence(realm.getName());
        File avatarFile = getAvatarFile(realm, user);
        if (avatarFile.exists()) {
            logger.debugf("Loading avatar file for user %s, file path is: %s", user.getUsername(),
                    avatarFile.getAbsolutePath());
        } else {
            logger.debugf("Avatar file not found for user %s", user.getUsername());
        }
        try {
            return new FileInputStream(avatarFile);
        } catch (FileNotFoundException e) {
            logger.debugf("Avatar file not found for user '%s' in realm '%s'", user.getUsername(), realm.getName());
            return null;
        }
    }

    private File getAvatarFile(RealmModel realm, UserModel user) {
        return new File(new File(avatarFolder, realm.getName()),
                useEmailAsFilename ? user.getEmail() : user.getUsername());
    }

    @Override
    public void deleteAvatarImage(RealmModel realm, UserModel user) {
        checkRealmFolderExistence(realm.getName());
        File avatarFile = getAvatarFile(realm, user);
        if (avatarFile.exists()) {
            logger.debugf("Deleting avatar file for user %s, file path is: %s", user.getUsername(),
                    avatarFile.getAbsolutePath());

            avatarFile.delete();
        } else {
            logger.debugf("Avatar file to delete not found for user %s", user.getUsername());
        }
    }

    @Override
    public void close() {
        // NOOP
    }

}
