package com.dimtion.shaarlier.activities;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Switch;
import android.widget.Toast;

import com.dimtion.shaarlier.R;
import com.dimtion.shaarlier.helpers.AccountsSource;
import com.dimtion.shaarlier.helpers.DebugHelper;
import com.dimtion.shaarlier.helpers.NetworkUtils;
import com.dimtion.shaarlier.services.NetworkService;
import com.dimtion.shaarlier.utils.ShaarliAccount;

import java.util.List;


public class AddAccountActivity extends AppCompatActivity {

    private String urlShaarli;
    private String username;
    private String password;
    private String restAPIKey;
    private String basicAuthUsername;
    private String basicAuthPassword;
    private String shortName;
    private ShaarliAccount account;
    private Boolean isDefaultAccount;
    private Boolean isValidateCert;

    private Boolean isEditing = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_account);

        Intent intent = getIntent();
        long accountId = intent.getLongExtra("_id", -1);

        if (accountId != -1) {
            isEditing = true;
            AccountsSource accountsSource = new AccountsSource(getApplicationContext());
            try {
                account = accountsSource.getShaarliAccountById(accountId);
            } catch (Exception e) { // Editing an account that does not exist, creating a new one
                account = null;
            }
            fillFields();
        } else {
            AccountsSource source = new AccountsSource(getApplicationContext());
            source.rOpen();
            List<ShaarliAccount> allAccounts = source.getAllAccounts();
            if (allAccounts.isEmpty()) {  // If it is the first account created
                CheckBox defaultCheck = findViewById(R.id.defaultAccountCheck);
                defaultCheck.setChecked(true);
                defaultCheck.setEnabled(false);
            }
        }
    }

    /**
    * Fill the fields with the selected account when editing a new account
    */
    private void fillFields() {
        // Get the user inputs :
        ((EditText) findViewById(R.id.urlShaarliView)).setText(account.getUrlShaarli());
        ((EditText) findViewById(R.id.usernameView)).setText(account.getUsername());
        ((EditText) findViewById(R.id.passwordView)).setText(account.getPassword());
        ((EditText) findViewById(R.id.shortNameView)).setText(account.getShortName());
        ((EditText) findViewById(R.id.restapiView)).setText(account.getRestAPIKey());

        ((Switch) findViewById(R.id.passwordAuthCheckbox)).setChecked(
                !(account.getRestAPIKey().length() > 0)
        );
        togglePasswordAuth(findViewById(R.id.passwordAuthCheckbox));

        if (!"".equals(account.getBasicAuthUsername())) {
            ((EditText) findViewById(R.id.basicUsernameView)).setText(account.getBasicAuthUsername());
            ((EditText) findViewById(R.id.basicPasswordView)).setText(account.getBasicAuthPassword());
            ((Switch) findViewById(R.id.basicAuthSwitch)).setChecked(true);
            enableBasicAuth(findViewById(R.id.basicAuthSwitch));
        }

        // default account?
        SharedPreferences prefs = getSharedPreferences(getString(R.string.params), MODE_PRIVATE);
        this.isDefaultAccount = (prefs.getLong(getString(R.string.p_default_account), -1) == account.getId());
        ((CheckBox) findViewById(R.id.defaultAccountCheck)).setChecked(this.isDefaultAccount);

        findViewById(R.id.deleteAccountButton).setVisibility(View.VISIBLE);
    }

    /**
     * Action which handle the press on the try and save button
     *
     * @param view: needed for binding with interface actions
     */
    public void tryAndSaveAction(View view) {
        hideKeyboard();
        findViewById(R.id.tryingConfSpinner).setVisibility(View.VISIBLE);
        findViewById(R.id.tryConfButton).setVisibility(View.GONE);

        // Get the user inputs:
        final String urlShaarliInput = ((EditText) findViewById(R.id.urlShaarliView)).getText().toString();
        this.username = ((EditText) findViewById(R.id.usernameView)).getText().toString();
        this.password = ((EditText) findViewById(R.id.passwordView)).getText().toString();
        this.restAPIKey = ((EditText) findViewById(R.id.restapiView)).getText().toString();
        if (((Switch) findViewById(R.id.basicAuthSwitch)).isChecked()) {
            this.basicAuthUsername = ((EditText) findViewById(R.id.basicUsernameView)).getText().toString();
            this.basicAuthPassword = ((EditText) findViewById(R.id.basicPasswordView)).getText().toString();
        } else {
            this.basicAuthUsername = "";
            this.basicAuthPassword = "";
        }
        this.shortName = ((EditText) findViewById(R.id.shortNameView)).getText().toString();
        this.isDefaultAccount = ((CheckBox) findViewById(R.id.defaultAccountCheck)).isChecked();
        this.isValidateCert = !((CheckBox) findViewById(R.id.disableCertValidation)).isChecked();

        this.urlShaarli = NetworkUtils.toUrl(urlShaarliInput);

        ((EditText) findViewById(R.id.urlShaarliView)).setText(this.urlShaarli);  // Update the view

        // Create a fake account:
        ShaarliAccount accountToTest = new ShaarliAccount();
        accountToTest.setUrlShaarli(this.urlShaarli);
        accountToTest.setUsername(this.username);
        accountToTest.setPassword(this.password);
        accountToTest.setRestAPIKey(this.restAPIKey);
        accountToTest.setValidateCert(this.isValidateCert);
        accountToTest.setBasicAuthUsername(this.basicAuthUsername);
        accountToTest.setBasicAuthPassword(this.basicAuthPassword);

        // Try the configuration
        Intent i = new Intent(this, NetworkService.class);
        i.putExtra("action", NetworkService.INTENT_CHECK);
        i.putExtra("account", accountToTest);
        i.putExtra(NetworkService.EXTRA_MESSENGER, new Messenger(new networkHandler(this)));
        startService(i);
    }

    /**
     * Handle the action of deletion: show a confirmation dialog then delete (if wanted)
     * @param view : The view needed for handling interface actions
     */
    public void deleteAccountAction(View view) {
        // Show dialog to confirm deletion
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(getString(R.string.text_confirm_deletion_account));
        builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                deleteAccount();
                finish();
            }
        });

        builder.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                // Just dismiss the dialog
            }
        });
        builder.show();
    }

    /**
     * Delete the selected account from the database
     */
    private void deleteAccount() {
        AccountsSource source = new AccountsSource(getApplicationContext());
        source.wOpen();
        source.deleteAccount(this.account);
        source.close();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_add_account, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_validate) {
            tryAndSaveAction(findViewById(id));
        }

        return super.onOptionsItemSelected(item);
    }

    /**
    * Obviously hide the keyboard
     * From: http://stackoverflow.com/a/7696791/1582589
    */
    private void hideKeyboard() {
        // Check if no view has focus:
        View view = this.getCurrentFocus();
        if (view != null) {
            InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
            inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

    public void enableBasicAuth(View toggle) {
        boolean checked = ((Switch) toggle).isChecked();
        findViewById(R.id.basicUsernameView).setEnabled(checked);
        findViewById(R.id.basicPasswordView).setEnabled(checked);
        findViewById(R.id.basicUsernameView).setVisibility(checked ? View.VISIBLE : View.GONE);
        findViewById(R.id.basicPasswordView).setVisibility(checked ? View.VISIBLE : View.GONE);
    }

    public void togglePasswordAuth(View toggle) {
        boolean checked = ((Switch) toggle).isChecked();
        findViewById(R.id.usernameView).setEnabled(checked);
        findViewById(R.id.usernameView).setVisibility(checked ? View.VISIBLE : View.GONE);

        findViewById(R.id.passwordView).setEnabled(checked);
        findViewById(R.id.passwordView).setVisibility(checked ? View.VISIBLE : View.GONE);

        findViewById(R.id.basicAuthSwitch).setEnabled(checked);
        findViewById(R.id.basicAuthSwitch).setVisibility(checked ? View.VISIBLE : View.GONE);

        findViewById(R.id.restapiView).setEnabled(!checked);
        findViewById(R.id.restapiView).setVisibility(!checked ? View.VISIBLE : View.GONE);
    }

    private class networkHandler extends Handler {
        private final Activity mParent;

        public networkHandler(Activity parent) {
            this.mParent = parent;
        }

        /**
         * Handle the arrival of a message coming from the network service.
         *
         * @param msg the message given by the service
         */
        @Override
        public void handleMessage(Message msg) {
            findViewById(R.id.tryConfButton).setVisibility(View.VISIBLE);
            findViewById(R.id.tryingConfSpinner).setVisibility(View.GONE);

            // Show the returned error
            switch (msg.arg1) {
                case NetworkService.NO_ERROR:
                    Toast.makeText(getApplicationContext(), R.string.success_test, Toast.LENGTH_LONG).show();
                    saveAccount();
                    finish();
                    break;
                case NetworkService.NETWORK_ERROR:
                    ((EditText) findViewById(R.id.urlShaarliView)).setError(getString(R.string.error_connecting));
                    enableSendReport((Exception) msg.obj);
                    break;
                case NetworkService.TOKEN_ERROR:
                    ((EditText) findViewById(R.id.urlShaarliView)).setError(getString(R.string.error_parsing_token));
                    enableSendReport(new Exception("TOKEN ERROR"));
                    break;
                case NetworkService.LOGIN_ERROR:
                    ((EditText) findViewById(R.id.usernameView)).setError(getString(R.string.error_login));
                    ((EditText) findViewById(R.id.passwordView)).setError(getString(R.string.error_login));
                    ((EditText) findViewById(R.id.restapiView)).setError(getString(R.string.error_login));
                    enableSendReport(new Exception("LOGIN ERROR"));
                    break;
                default:
                    ((EditText) findViewById(R.id.urlShaarliView)).setError(getString(R.string.error_unknown));
                    Toast.makeText(getApplicationContext(), R.string.error_unknown, Toast.LENGTH_LONG).show();
                    enableSendReport(new Exception("UNKNOWN ERROR"));
                    break;
            }
        }

        private void enableSendReport(final Exception error) {
            Button reportButton = findViewById(R.id.sendReportButton);
            reportButton.setVisibility(View.VISIBLE);
            reportButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    AlertDialog.Builder builder = new AlertDialog.Builder(mParent);

                    builder.setMessage(R.string.report_issue).setTitle("REPORT - Shaarlier");

                    final String extra = "Url Shaarli: " + urlShaarli;

                    builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            DebugHelper.sendMailDev(mParent, "REPORT - Shaarlier", DebugHelper.generateReport(error, mParent, extra));
                        }
                    });
                    builder.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            // User cancelled the dialog
                        }
                    });
                    AlertDialog dialog = builder.create();
                    dialog.show();
                }
            });
        }
    }

    /**
     * Save a new account into the database,
     * should be called only if the account was verified.
     */
    private void saveAccount() {
        AccountsSource accountsSource = new AccountsSource(getApplicationContext());
        accountsSource.wOpen();
        try {
            if (isEditing) {  // Only update the database
                account.setUrlShaarli(this.urlShaarli);
                account.setUsername(this.username);
                account.setPassword(this.password);
                account.setBasicAuthUsername(this.basicAuthUsername);
                account.setBasicAuthPassword(this.basicAuthPassword);
                account.setShortName(this.shortName);
                account.setValidateCert(this.isValidateCert);
                account.setRestAPIKey(this.restAPIKey);
                accountsSource.editAccount(account);
            } else {
                this.account = accountsSource.createAccount(
                        this.urlShaarli,
                        this.username,
                        this.password,
                        this.basicAuthUsername,
                        this.basicAuthPassword,
                        this.shortName,
                        this.isValidateCert,
                        this.restAPIKey
                );
            }
        } catch (Exception e) {
            Log.e("ENCRYPTION ERROR", e.getMessage());
        } finally {
            accountsSource.close();
        }

        // Set the default account if needed
        if (this.isDefaultAccount) {
            SharedPreferences prefs = getSharedPreferences(getString(R.string.params), MODE_PRIVATE);
            SharedPreferences.Editor editor = prefs.edit();

            editor.putLong(getString(R.string.p_default_account), this.account.getId());
            editor.apply();
        }
    }
}