package com.github.andlyticsproject;

import android.support.v7.app.AppCompatActivity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.widget.Toast;
import android.widget.ViewSwitcher;

import com.github.andlyticsproject.admob.AdmobAccountRemovedException;
import com.github.andlyticsproject.admob.AdmobAskForPasswordException;
import com.github.andlyticsproject.admob.AdmobGenericException;
import com.github.andlyticsproject.admob.AdmobInvalidRequestException;
import com.github.andlyticsproject.admob.AdmobInvalidTokenException;
import com.github.andlyticsproject.admob.AdmobRateLimitExceededException;
import com.github.andlyticsproject.console.AppAccessBlockedException;
import com.github.andlyticsproject.console.AuthenticationException;
import com.github.andlyticsproject.console.DevConsoleProtocolException;
import com.github.andlyticsproject.console.MultiAccountException;
import com.github.andlyticsproject.console.NetworkException;
import com.github.andlyticsproject.dialog.CrashDialog;
import com.github.andlyticsproject.dialog.CrashDialog.CrashDialogBuilder;
import com.github.andlyticsproject.util.Utils;
import com.google.android.gms.common.GooglePlayServicesUtil;

import org.acra.ACRA;

public class BaseActivity extends AppCompatActivity {

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

	public static final String EXTRA_AUTH_ACCOUNT_NAME = "com.github.andlyticsproject.accontname";
	public static final String EXTRA_PACKAGE_NAME = "com.github.andlyticsproject.packagename";
	public static final String EXTRA_DEVELOPER_ID = "com.github.andlyticsproject.developerid";
	public static final String EXTRA_ICON_FILE = "com.github.andlyticsproject.iconfile";

	public static final int REQUEST_GOOGLE_PLAY_SERVICES = 0;
	public static final int REQUEST_AUTHORIZATION = 1;
	public static final int REQUEST_ACCOUNT_PICKER = 2;

	protected static final int REQUEST_AUTHENTICATE = 42;

	protected String packageName;
	protected String developerId;
	protected String iconFilePath;
	protected String accountName;

	private boolean refreshing;

	private boolean skipMainReload;

	protected DeveloperAccountManager developerAccountManager;


	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		developerAccountManager = DeveloperAccountManager.getInstance(getApplication());

		Bundle b = getIntent().getExtras();
		if (b != null) {
			// TODO move packageName and iconFilePath assignments to
			// BaseDetailsActivity
			// Will this effect startActivity etc with regard to null behaviour?
			// Might be best to leave them here
			packageName = b.getString(BaseActivity.EXTRA_PACKAGE_NAME);
			developerId = b.getString(BaseActivity.EXTRA_DEVELOPER_ID);
			iconFilePath = b.getString(BaseActivity.EXTRA_ICON_FILE);
			accountName = b.getString(BaseActivity.EXTRA_AUTH_ACCOUNT_NAME);
			developerAccountManager.selectDeveloperAccount(accountName);
		}

	}

	public void startActivity(Class<?> clazz, boolean disableAnimation, boolean skipDataReload) {
		Intent intent = new Intent(BaseActivity.this, clazz);
		intent.putExtra(BaseActivity.EXTRA_PACKAGE_NAME, packageName);
		intent.putExtra(BaseActivity.EXTRA_DEVELOPER_ID, developerId);
		intent.putExtra(BaseActivity.EXTRA_ICON_FILE, iconFilePath);
		intent.putExtra(BaseActivity.EXTRA_AUTH_ACCOUNT_NAME, accountName);
		if (clazz.equals(Main.class)) {
			// Main does not have singleTask set in the manifest
			// in order to facilitate easy switching between accounts using list
			// navigation
			// We therefore need to clear activity we came from before had in
			// order
			// to avoid duplicates
			intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		}
		if (disableAnimation) {
			intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
		}
		if (skipDataReload) {
			setSkipMainReload(true);
		}

		startActivity(intent);
	}

	public void handleUserVisibleException(Exception e) {
		if (e instanceof NetworkException) {
			Toast.makeText(BaseActivity.this, getString(R.string.network_error), Toast.LENGTH_LONG)
					.show();
		} else if (e instanceof AppAccessBlockedException) {
			Toast.makeText(BaseActivity.this, getString(R.string.app_access_blocked_error, accountName),
					Toast.LENGTH_LONG).show();
		} else if (e instanceof AuthenticationException) {
			Toast.makeText(BaseActivity.this, getString(R.string.auth_error, accountName),
					Toast.LENGTH_LONG).show();
		} else if (e instanceof AdmobRateLimitExceededException) {
			Toast.makeText(BaseActivity.this, getString(R.string.admob_ratelimit_error),
					Toast.LENGTH_LONG).show();
		} else if (e instanceof AdmobAskForPasswordException) {
			Log.w(TAG, "ask for admob credentials");
			setSkipMainReload(true);
		} else if (e instanceof AdmobAccountRemovedException) {
			String wrongAccount = ((AdmobAccountRemovedException) e).getAccountName();
			Toast.makeText(BaseActivity.this,
					getString(R.string.admob_missing_error, wrongAccount), Toast.LENGTH_LONG)
					.show();
		} else if (e instanceof AdmobInvalidRequestException) {
			Toast.makeText(BaseActivity.this, getString(R.string.admob_invalid_request_error),
					Toast.LENGTH_LONG).show();
		} else if (e instanceof AdmobInvalidTokenException) {
			Toast.makeText(BaseActivity.this, getString(R.string.admob_invalid_token_error),
					Toast.LENGTH_LONG).show();
		} else if (e instanceof AdmobGenericException) {
			Log.w(TAG, e.getMessage(), e);
			Toast.makeText(BaseActivity.this, getString(R.string.admob_generic_error),
					Toast.LENGTH_LONG).show();
		} else if (e instanceof DevConsoleProtocolException) {
			int appVersionCode = Utils.getAppVersionCode(this);
			if (Preferences.getLatestVersionCode(this) > appVersionCode) {
				showNewVersionDialog(e);
			} else {
				showGoogleErrorDialog(e);
			}
		} else if (e instanceof MultiAccountException) {
			showAspErrorDialog(e);
		} else {
			showCrashDialog(e);
		}

	}

	private void showNewVersionDialog(Exception e) {
		if (!isFinishing()) {

			CrashDialog.CrashDialogBuilder builder = new CrashDialogBuilder(this);
			builder.setTitle(getString(R.string.update_required_title));
			builder.setMessage(R.string.newversion_desc);
			builder.setPositiveButton(getString(R.string.update_button),
					new DialogInterface.OnClickListener() {

						public void onClick(DialogInterface dialog, int which) {

							Intent goToMarket = null;
							goToMarket = new Intent(Intent.ACTION_VIEW, Uri
									.parse(getString(R.string.market_uri)));
							startActivity(goToMarket);

							dialog.dismiss();
						}

					});
			builder.setNegativeButton(getString(R.string.cancel),
					new DialogInterface.OnClickListener() {

						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();
						}

					});

			builder.create().show();
		}

	}

	protected void showCrashDialog(final Exception e) {

		if (!isFinishing()) {

			CrashDialog.CrashDialogBuilder builder = new CrashDialogBuilder(this);
			builder.setTitle(getString(R.string.crash_dialog_title));
			builder.setMessage(R.string.crash_desc);
			builder.setPositiveButton(getString(R.string.send_report_button),
					new DialogInterface.OnClickListener() {

						public void onClick(DialogInterface dialog, int which) {

							if (!isFinishing()) {

								Thread thread = new Thread(new Runnable() {

									@Override
									public void run() {
										sendAracReport(e, true);
									}

								});
								thread.run();
								dialog.dismiss();
							}

						}

					});
			builder.setNegativeButton(getString(R.string.cancel),
					new DialogInterface.OnClickListener() {

						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();
						}

					});

			builder.create().show();
		}

	}

	private void sendAracReport(Exception e, boolean userTriggered) {
		ACRA.getErrorReporter().handleSilentException(e);
	}

	protected void showGoogleErrorDialog(final Exception e) {

		if (!isFinishing()) {

			CrashDialog.CrashDialogBuilder builder = new CrashDialogBuilder(this);
			builder.setTitle(getString(R.string.crash_dialog_title));
			builder.setMessage(getString(R.string.remote_interface_changed_error));
			builder.setPositiveButton(getString(R.string.send_report_button),
					new DialogInterface.OnClickListener() {

						public void onClick(DialogInterface dialog, int which) {

							Thread thread = new Thread(new Runnable() {

								@Override
								public void run() {
									sendAracReport(e, true);
								}
							});
							thread.run();
							dialog.dismiss();
						}

					});
			builder.setNegativeButton(getString(R.string.cancel),
					new DialogInterface.OnClickListener() {

						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();
						}

					});

			builder.create().show();

		}

	}

	protected void showAspErrorDialog(final Exception e) {

		if (!isFinishing()) {

			CrashDialog.CrashDialogBuilder builder = new CrashDialogBuilder(this);
			builder.setTitle(getString(R.string.multiple_dev_accounts_title));
			builder.setMessage(getString(R.string.multiple_dev_accounts_error));
			builder.setPositiveButton(getString(R.string.logout),
					new DialogInterface.OnClickListener() {

						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();
							developerAccountManager.unselectDeveloperAccount();
							Preferences.saveSkipAutoLogin(BaseActivity.this, true);
							Intent intent = new Intent(BaseActivity.this, LoginActivity.class);
							startActivity(intent);
							overridePendingTransition(R.anim.activity_fade_in,
									R.anim.activity_fade_out);

						}

					});
			builder.setNegativeButton(getString(R.string.cancel),
					new DialogInterface.OnClickListener() {

						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();
							developerAccountManager.unselectDeveloperAccount();
							Preferences.saveSkipAutoLogin(BaseActivity.this, true);
							Intent intent = new Intent(BaseActivity.this, LoginActivity.class);
							startActivity(intent);
							overridePendingTransition(R.anim.activity_fade_in,
									R.anim.activity_fade_out);
						}

					});

			builder.create().show();

		}

	}

	public ContentAdapter getDbAdapter() {
		return getAndlyticsApplication().getDbAdapter();
	}

	protected void showLoadingIndicator(ViewSwitcher switcher) {
		Animation loadingAnim = AnimationUtils.loadAnimation(this, R.anim.loading);
		loadingAnim.setInterpolator(new LinearInterpolator());

		switcher.showNext();
	}

	protected void hideLoadingIndicator(ViewSwitcher switcher) {
		switcher.showPrevious();
	}

	public AndlyticsApp getAndlyticsApplication() {
		return (AndlyticsApp) getApplication();
	}

	public boolean shouldRemoteUpdateStats() {
		long now = System.currentTimeMillis();
		long lastUpdate = developerAccountManager.getLastStatsRemoteUpdateTime(accountName);
		// never updated
		if (lastUpdate == 0) {
			return true;
		}

		return (now - lastUpdate) >= Preferences.STATS_REMOTE_UPDATE_INTERVAL;
	}

	public boolean isRefreshing() {
		return refreshing;
	}

	public void refreshStarted() {
		ensureMainThread();

		refreshing = true;
		invalidateOptionsMenu();
	}

	public void refreshFinished() {
		ensureMainThread();

		refreshing = false;
		invalidateOptionsMenu();
	}

	private void ensureMainThread() {
		Looper looper = Looper.myLooper();
		if (looper != null && looper != getMainLooper()) {
			throw new IllegalStateException("Only call this from your main thread.");
		}
	}

	protected void setSkipMainReload(boolean skipMainReload) {
		this.skipMainReload = skipMainReload;
	}

	protected boolean isSkipMainReload() {
		return skipMainReload;
	}

	public String getPackage() {
		return packageName;
	}

	public String getDeveloperId() {
		return developerId;
	}

	public String getAccountName() {
		return accountName;
	}

	protected boolean checkGooglePlayServicesAvailable() {
		int connectionStatusCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
		if (GooglePlayServicesUtil.isUserRecoverableError(connectionStatusCode)) {
			showGooglePlayServicesAvailabilityErrorDialog(connectionStatusCode);
			return false;
		}
		return true;
	}

	private void showGooglePlayServicesAvailabilityErrorDialog(final int connectionStatusCode) {
		runOnUiThread(new Runnable() {
			public void run() {
				Dialog dialog = GooglePlayServicesUtil.getErrorDialog(connectionStatusCode,
						BaseActivity.this, REQUEST_GOOGLE_PLAY_SERVICES);
				dialog.show();
			}
		});
	}

}
