package io.codetail;

import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;

import java.util.List;

import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.OnClick;
import codetail.text.MaterialEditText;
import codetail.widget.Toolbar;
import io.codetail.client.auth.Authenticator;
import io.codetail.sources.Source;
import io.codetail.watchme.R;

import static android.accounts.AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE;
import static android.accounts.AccountManager.KEY_ACCOUNT_TYPE;
import static android.accounts.AccountManager.KEY_AUTHTOKEN;
import static android.accounts.AccountManager.KEY_ERROR_CODE;
import static io.codetail.client.auth.Authenticator.AuthenticationEvent;
import static io.codetail.client.auth.BasicAccountAuthenticator.ACTION_AUTHENTICATE;
import static io.codetail.client.auth.BasicAccountAuthenticator.ERROR_CODE_INVALID_USER_DATA;
import static io.codetail.fragments.NavigationFragment.USER_PICTURE_URL;

public class AuthenticationActivity extends WatchMeActivity{

    Bus mEventBus;

    @InjectView(R.id.username)
    MaterialEditText mUsernameField;

    @InjectView(R.id.password)
    MaterialEditText mPasswordField;

    @InjectView(R.id.login)
    View mSignIn;

    @InjectView(R.id.headline)
    TextView mHeadline;

    @InjectView(R.id.description)
    TextView mDescription;

    Authenticator mAuthenticator;
    AccountAuthenticatorResponse mAuthenticatorResponse;
    String mSourceId;

    Account mAccount;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_auth);
        ButterKnife.inject(this);
        mEventBus = Constants.getEventBus();

        final Intent intent = getIntent();
        final String action = intent.getAction();

        if(!ACTION_AUTHENTICATE.equals(action)){
            throw new RuntimeException("Only authentication supported");
        }

        mAuthenticatorResponse = intent.getParcelableExtra(KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);
        mSourceId = intent.getStringExtra(KEY_ACCOUNT_TYPE);

        if(mSourceId == null){
            throw new NullPointerException("Account type is not given");
        }

        List<Source> sources = WatchMeApplication.getApplication().getSources();
        for(Source source : sources){
            if(source.getSourceId().equals(mSourceId)){
                mAuthenticator = source.getAuthenticator();
            }
        }

        if(mAuthenticator == null){
            throw new NullPointerException(String.format("Source for %s not found", mSourceId));
        }

        if(mAuthenticatorResponse != null){
            mAuthenticatorResponse.onRequestContinued();
        }

        mHeadline.setText(mAuthenticator.getHeadline());
        mDescription.setText(mAuthenticator.getDescription());
    }

    @Override
    protected void onStart() {
        super.onStart();
        mEventBus.register(this);
    }

    @OnClick(R.id.login)
    public void canLogin(){
        if(!mUsernameField.isCharactersCountValid()){
            mUsernameField.setError(getString(R.string.sign_in_field_must_be_more_than_4_chars));
        }

        if(!mPasswordField.isCharactersCountValid()){
            mPasswordField.setError(getString(R.string.sign_in_field_must_be_more_than_4_chars));
        }

        if(mUsernameField.isCharactersCountValid() && mPasswordField.isCharactersCountValid()){
            mUsernameField.setError(null);
            mPasswordField.setError(null);

            tryAuthenticateUser();
        }

    }

    public void tryAuthenticateUser(){
        setLockForm(true);

        String username = mUsernameField.getText().toString();
        String password = mPasswordField.getText().toString();

        mAccount = new Account(username,  mSourceId);

        mAuthenticator.login(mAccount, password);
    }

    @Subscribe
    public void onEvent(AuthenticationEvent event){
        Bundle result = event.getResult();
        setLockForm(false);

        if(event.isSuccess()){
            String password = mPasswordField.getText().toString();
            AccountManager manager = AccountManager.get(this);

            Bundle userData = new Bundle();
            userData.putString(USER_PICTURE_URL, result.getString(USER_PICTURE_URL));

            manager.addAccountExplicitly(mAccount, password, userData);
            manager.setAuthToken(mAccount, mSourceId, result.getString(KEY_AUTHTOKEN));

            mAuthenticatorResponse.onResult(result);
            mAuthenticatorResponse = null;

            setResult(RESULT_OK);
            finish();

        }else{
            int errorCode = result.getInt(KEY_ERROR_CODE);

            if(errorCode == ERROR_CODE_INVALID_USER_DATA){
                mUsernameField.setError(getString(R.string.sign_in_failed_with_wrong_data_username));
                mPasswordField.setError(getString(R.string.sign_in_failed_with_wrong_data_password));
            }
        }
    }

    void setLockForm(boolean lockForm){
        mUsernameField.setEnabled(!lockForm);
        mPasswordField.setEnabled(!lockForm);

        mSignIn.setEnabled(!lockForm);
    }

    public void cancel(){
        mAuthenticatorResponse.onError(AccountManager.ERROR_CODE_CANCELED, "cancelled");
        mAuthenticatorResponse = null;
        setResult(RESULT_CANCELED);
        super.finish();
    }

    @Override
    protected void onStop() {
        super.onStop();
        ButterKnife.reset(this);
        mEventBus.unregister(this);
    }

    @Override
    public void onBackPressed() {
        cancel();
    }

    @Override
    public void setNavigationLockMode(boolean lockMode) {
        throw new UnsupportedOperationException("Lock mode is unsupported");
    }

    @Override
    public Toolbar getToolbar() {
        throw new UnsupportedOperationException("No toolbar provided");
    }
}