package com.github.andlyticsproject;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.support.v7.app.AppCompatActivity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.github.andlyticsproject.model.DeveloperAccount;
import com.github.andlyticsproject.sync.AutosyncHandler;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Used for initial login and managing accounts Because of this original legacy as the launcher
 * activity, navigation is a little odd.
 * On first startup: LoginActivity -> Main
 * When managing
 * accounts: Main -> LoginActivity <- Main
 * or
 * Main -> LoginActivity -> Main
 */
public class LoginActivity extends AppCompatActivity {

	private static final String TAG = LoginActivity.class.getSimpleName();

	public static final String EXTRA_MANAGE_ACCOUNTS_MODE = "com.github.andlyticsproject.manageAccounts";

	public static final String AUTH_TOKEN_TYPE_ANDROID_DEVELOPER = "androiddeveloper";

	protected static final int CREATE_ACCOUNT_REQUEST = 1;

	private List<DeveloperAccount> developerAccounts;

	private boolean manageAccountsMode = false;
	private boolean blockGoingBack = false;
	private DeveloperAccount selectedAccount = null;
	private View okButton;
	private LinearLayout accountList;

	private AccountManager accountManager;
	private DeveloperAccountManager developerAccountManager;
	private AutosyncHandler syncHandler;

	// TODO Clean this code and res/layout/login.xml up e.g. using a ListView
	// instead of a LinearLayout
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		accountManager = AccountManager.get(this);
		developerAccountManager = DeveloperAccountManager.getInstance(getApplicationContext());
		syncHandler = new AutosyncHandler();

		// When called from accounts action item in Main, this flag is passed to
		// indicate
		// that LoginActivity should not auto login as we are managing the
		// accounts,
		// rather than performing the initial login
		Bundle extras = getIntent().getExtras();
		if (extras != null) {
			manageAccountsMode = extras.getBoolean(LoginActivity.EXTRA_MANAGE_ACCOUNTS_MODE);
		}

		selectedAccount = developerAccountManager.getSelectedDeveloperAccount();

		setContentView(R.layout.login);
		setProgressBarIndeterminateVisibility(false);

		if (manageAccountsMode) {
			getSupportActionBar().setDisplayHomeAsUpEnabled(true);
			getSupportActionBar().setTitle(R.string.manage_accounts);
		}

		accountList = (LinearLayout) findViewById(R.id.login_input);

		okButton = findViewById(R.id.login_ok_button);
		okButton.setClickable(true);
		okButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				new AsyncTask<Void, Void, Void>() {

					@Override
					protected void onPreExecute() {
						setProgressBarIndeterminateVisibility(true);
						okButton.setEnabled(false);
					}

					@Override
					protected Void doInBackground(Void... args) {
						saveDeveloperAccounts();

						return null;
					}

					@Override
					protected void onPostExecute(Void arg) {
						setProgressBarIndeterminateVisibility(false);
						okButton.setEnabled(true);

						if (selectedAccount != null) {
							redirectToMain(selectedAccount.getName(),
									selectedAccount.getDeveloperId());
						} else {
							// Go to the first non hidden account
							for (DeveloperAccount account : developerAccounts) {
								if (account.isVisible()) {
									redirectToMain(account.getName(), account.getDeveloperId());
									break;
								}
							}
						}
					}
				}.execute();
			}
		});
	}

	@Override
	protected void onResume() {
		super.onResume();

		boolean skipAutologin = Preferences.getSkipAutologin(this);

		if (!manageAccountsMode & !skipAutologin & selectedAccount != null) {
			redirectToMain(selectedAccount.getName(), selectedAccount.getDeveloperId());
		} else {
			showAccountList();
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		getMenuInflater().inflate(R.menu.login_menu, menu);
		return true;
	}

	/**
	 * Called if item in option menu is selected.
	 * 
	 * @param item
	 *            The chosen menu item
	 * @return boolean true/false
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
			case R.id.itemLoginmenuAdd:
				addNewGoogleAccount();
				break;
			case android.R.id.home:
				if (!blockGoingBack) {
					setResult(RESULT_OK);
					finish();
				}
				break;
			default:
				return false;
		}
		return true;
	}

	@Override
	public void onBackPressed() {
		setResult(blockGoingBack ? RESULT_CANCELED : RESULT_OK);
		super.onBackPressed();
	}

	protected void showAccountList() {
		Account[] googleAccounts = accountManager.getAccountsByType(AutosyncHandler.ACCOUNT_TYPE_GOOGLE);
		List<DeveloperAccount> dbAccounts = developerAccountManager.getAllDeveloperAccounts();
		developerAccounts = new ArrayList<DeveloperAccount>();

		accountList.removeAllViews();
		for (int i = 0; i < googleAccounts.length; i++) {
			DeveloperAccount developerAccount = DeveloperAccount
					.createHidden(googleAccounts[i].name);
			int idx = dbAccounts.indexOf(developerAccount);
			// use persistent object if exists
			if (idx != -1) {
				developerAccount = dbAccounts.get(idx);
			}
			developerAccounts.add(developerAccount);

			// Setup auto sync
			// only do this when managing accounts, otherwise sync may start
			// in the background before accounts are actually configured
			if (manageAccountsMode) {
				// Ensure it matches the sync period (excluding disabled state)
				syncHandler.setAutosyncPeriod(googleAccounts[i].name,
						Preferences.getLastNonZeroAutosyncPeriod(this));
				// Now make it match the master sync (including disabled state)
				syncHandler.setAutosyncPeriod(googleAccounts[i].name,
						Preferences.getAutosyncPeriod(this));
			}

			View accountItem = getLayoutInflater().inflate(R.layout.login_list_item, null);
			TextView accountName = (TextView) accountItem.findViewById(R.id.login_list_item_text);
			accountName.setText(googleAccounts[i].name);
			accountItem.setTag(developerAccount);
			CheckBox enabled = (CheckBox) accountItem.findViewById(R.id.login_list_item_enabled);
			enabled.setChecked(!developerAccount.isHidden());
			enabled.setOnCheckedChangeListener(new OnCheckedChangeListener() {
				@Override
				public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
					DeveloperAccount account = (DeveloperAccount) ((View) buttonView.getParent())
							.getTag();
					if (isChecked) {
						account.activate();
					} else {
						account.hide();
					}

					if (manageAccountsMode && account.equals(selectedAccount)) {
						// If they remove the current account, then stop them
						// going back
						blockGoingBack = account.isHidden();
					}

					okButton.setEnabled(isAtLeastOneAccountEnabled());
				}
			});
			accountList.addView(accountItem);
		}

		// Update ok button
		okButton.setEnabled(isAtLeastOneAccountEnabled());
	}

	private void saveDeveloperAccounts() {
		for (DeveloperAccount account : developerAccounts) {
			if (account.isHidden()) {
				// They are removing the account from Andlytics, disable
				// syncing
				syncHandler.setAutosyncEnabled(account.getName(), false);
			} else {
				// Make it match the master sync period (including
				// disabled state)
				syncHandler.setAutosyncPeriod(account.getName(),
						Preferences.getAutosyncPeriod(LoginActivity.this));
			}
			developerAccountManager.addOrUpdateDeveloperAccount(account);
		}
	}

	private boolean isAtLeastOneAccountEnabled() {
		for (DeveloperAccount acc : developerAccounts) {
			if (acc.isVisible()) {
				return true;
			}
		}

		return false;
	}

	private void addNewGoogleAccount() {
		AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
			public void run(AccountManagerFuture<Bundle> future) {
				try {
					Bundle bundle = future.getResult();
					bundle.keySet();
					Log.d(TAG, "account added: " + bundle);

					showAccountList();

				} catch (OperationCanceledException e) {
					Log.d(TAG, "addAccount was canceled");
				} catch (IOException e) {
					Log.d(TAG, "addAccount failed: " + e);
				} catch (AuthenticatorException e) {
					Log.d(TAG, "addAccount failed: " + e);
				}
				// gotAccount(false);
			}
		};

		// TODO request a weblogin: token here, so we have it cached?
		accountManager.addAccount(AutosyncHandler.ACCOUNT_TYPE_GOOGLE,
				LoginActivity.AUTH_TOKEN_TYPE_ANDROID_DEVELOPER, null, null /* options */,
				LoginActivity.this, callback, null /* handler */);
	}

	private void redirectToMain(String selectedAccount, String developerId) {
		Preferences.saveSkipAutoLogin(this, false);
		Intent intent = new Intent(LoginActivity.this, Main.class);
		intent.putExtra(BaseActivity.EXTRA_AUTH_ACCOUNT_NAME, selectedAccount);
		intent.putExtra(BaseActivity.EXTRA_DEVELOPER_ID, developerId);
		intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		startActivity(intent);
		overridePendingTransition(R.anim.activity_fade_in, R.anim.activity_fade_out);
		finish();
	}

}
