package de.sebse.fuplanner.tools;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;

import java.io.IOException;

import androidx.annotation.Nullable;
import de.sebse.fuplanner.services.kvv.Login;
import de.sebse.fuplanner.tools.logging.Logger;

public class CustomAccountManager {
    private final AccountManager mAccountManager;
    private final ActivityInterface mActivityInterface;
    private Logger log = new Logger(this);

    public CustomAccountManager(AccountManager manager, ActivityInterface activityInterface) {
        mAccountManager = manager;
        this.mActivityInterface = activityInterface;
    }





    public void doInvalidateTokenSync(String accountType, String authTokenType) {
        Account account = mAccountManager.getAccountsByType(accountType)[0];
        try {
            String token = mAccountManager.blockingGetAuthToken(account, authTokenType, true);
            mAccountManager.invalidateAuthToken(accountType, token);
        } catch (AuthenticatorException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (OperationCanceledException e) {
            e.printStackTrace();
        }
    }

    public void doInvalidateToken(String accountType, String authTokenType, Login.BooleanInterface callback) {
        Account account = mAccountManager.getAccountsByType(accountType)[0];
        mAccountManager.getAuthToken(account, authTokenType, null, true, accountManagerFuture -> {
            try {
                Bundle bnd = accountManagerFuture.getResult();
                String token = bnd.getString(AccountManager.KEY_AUTHTOKEN);
                mAccountManager.invalidateAuthToken(accountType, token);
                if (callback != null)
                    callback.run(true);
                return;
            } catch (AuthenticatorException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (OperationCanceledException e) {
                e.printStackTrace();
            }
            if (callback != null)
                callback.run(false);
        }, null);
    }

    public void deleteAccount(String accountType) {
        Account[] accounts = mAccountManager.getAccountsByType(accountType);
        int[] count = {accounts.length};
        for (Account account: accounts) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
                mAccountManager.removeAccount(account, null, null, null);
            } else {
                mAccountManager.removeAccount(account, null, null);
            }
        }
    }

    public void getTokenByType(String accountType, String authTokenType, @Nullable StringInterface callback) {
        Activity activity = mActivityInterface.get();
        AccountManagerCallback<Bundle> cb = (accountManagerFuture -> {
            try {
                Bundle bnd = accountManagerFuture.getResult();
                final String authtoken = bnd.getString(AccountManager.KEY_AUTHTOKEN);
                if (callback != null)
                    callback.run(authtoken);
                return;
            } catch (AuthenticatorException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (OperationCanceledException e) {
                e.printStackTrace();
            }
            if (callback != null)
                callback.run(null);
        });
        if (activity != null) {
            mAccountManager.getAuthTokenByFeatures(accountType, authTokenType, null, mActivityInterface.get(), null, null, cb, null);
        } else {
            Account account = mAccountManager.getAccountsByType(accountType)[0];
            mAccountManager.getAuthToken(account, authTokenType, null, true, cb, null);
        }
    }

    public String getTokenByTypeSync(String accountType, String authTokenType) {
        Account account = mAccountManager.getAccountsByType(accountType)[0];
        try {
            return  mAccountManager.blockingGetAuthToken(account, authTokenType, true);
        } catch (AuthenticatorException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (OperationCanceledException e) {
            e.printStackTrace();
        }
        return null;
    }

    public boolean hasAccounts(String accountType) {
        return mAccountManager.getAccountsByType(accountType).length != 0;
    }

    public Account getAccountByType(String accountType) {
        Account[] accountsByType = mAccountManager.getAccountsByType(accountType);
        if (accountsByType.length > 0)
            return accountsByType[0];
        return null;
    }

    @FunctionalInterface
    public interface ActivityInterface {
        @Nullable
        Activity get();
    }

    public interface StringInterface {
        void run(@Nullable String string);
    }
}
