package de.sebse.fuplanner.services.fulogin;

import android.accounts.AccountManager;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Build;

import org.jetbrains.annotations.NotNull;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;

import androidx.annotation.Nullable;
import de.sebse.fuplanner.R;
import de.sebse.fuplanner.services.kvv.sync.BBLogin;
import de.sebse.fuplanner.services.kvv.sync.FULogin;
import de.sebse.fuplanner.services.kvv.sync.KVVLogin;
import de.sebse.fuplanner.tools.logging.Logger;
import de.sebse.fuplanner.tools.network.NetworkError;
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;


/**
 * Represents an asynchronous login/registration task used to authenticate
 * the user.
 */
public class UserLoginTask extends AsyncTask<Void, Void, String> {

    /**
     * A dummy authentication store containing known user names and passwords.
     * TODO: remove after connecting to a real authentication system.
     */
    /*private static final String[] DUMMY_CREDENTIALS = new String[]{
            "foo@example.com:hello", "bar@example.com:world"
    };*/
    static final String PARAM_USER_PASS = "PARAM_USER_PASS";

    private final String mUsername;
    private final String mPassword;
    private final KVVLogin mKVVLogin;
    private final BBLogin mBBLogin;
    private String mTokenType;
    private Logger log = new Logger(this);
    @SuppressLint("StaticFieldLeak")
    @Nullable
    private FUAuthenticatorActivity mActivity;

    UserLoginTask(String username, String password, @NotNull String tokenType, @NotNull Context context) {
        mUsername = username;
        mPassword = password;
        mTokenType = tokenType;
        FULogin mFULogin = new FULogin(context);
        mKVVLogin = new KVVLogin(context, mFULogin);
        mBBLogin = new BBLogin(context, mFULogin);
        if (context instanceof FUAuthenticatorActivity)
            mActivity = (FUAuthenticatorActivity) context;
    }

    @Override
    protected String doInBackground(Void... params) {
        // TODO: attempt authentication against a network service.

        CountDownLatch latch = new CountDownLatch(1);
        AtomicReference<String> login = new AtomicReference<>();
        NetworkErrorCallback errorFunc = error -> {
            log.e(error);
            login.set("Error: "+String.valueOf(error.getCode()));
            latch.countDown();
        };
        switch (mTokenType) {
            case AccountGeneral.AUTHTOKEN_TYPE_KVV:
                mKVVLogin.doLogin(mUsername, mPassword, success -> {
                    mKVVLogin.testLoginToken(success, success1 -> {
                        login.set(success1.toJsonString());
                        latch.countDown();
                    }, errorFunc);
                }, errorFunc);
                break;
            case AccountGeneral.AUTHTOKEN_TYPE_BLACKBOARD:
                mBBLogin.doLogin(mUsername, mPassword, success -> {
                    mBBLogin.testLoginToken(success, success1 -> {
                        login.set(success1.toJsonString());
                        latch.countDown();
                    }, error -> {
                        if (error.getCode() == 100270) {
                            // Blackboard never used
                            success.setNotAvailable();
                            login.set(success.toJsonString());
                            latch.countDown();
                        } else {
                            errorFunc.onError(error);
                        }
                    });
                }, errorFunc);
                break;
            default:
                errorFunc.onError(new NetworkError(104100, 400, "Invalid auth token type"));
                return null;
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return login.get();
    }

    @Override
    protected void onPostExecute(final String success) {
        if (mActivity == null || mActivity.isFinishing())
            return;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && mActivity.isDestroyed())
            return;
        mActivity.mAuthTask = null;
        mActivity.showProgress(false);

        if (success != null && !success.startsWith("Error: ")) {
            final Intent res = new Intent();
            res.putExtra(AccountManager.KEY_ACCOUNT_NAME, mUsername);
            res.putExtra(AccountManager.KEY_ACCOUNT_TYPE, AccountGeneral.ACCOUNT_TYPE);
            res.putExtra(AccountManager.KEY_AUTHTOKEN, success);
            res.putExtra(PARAM_USER_PASS, mPassword);
            mActivity.finishLogin(res);
        } else if (success != null && (success.contains("100343"))) {
            mActivity.mPasswordView.setError(mActivity.getString(R.string.error_incorrect_password));
            mActivity.mPasswordView.requestFocus();
        } else if (success != null) {
            mActivity.mErrorView.setText(mActivity.getString(R.string.network_error_parameter, success.substring(7)));
        } else {
            mActivity.mErrorView.setText(R.string.network_error);
        }
    }

    @Override
    protected void onCancelled() {
        if (mActivity == null || mActivity.isFinishing())
            return;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && mActivity.isDestroyed())
            return;
        mActivity.mAuthTask = null;
        mActivity.showProgress(false);
    }
}