/**
 * Wi-Fi в метро (pw.thedrhax.mosmetro, Moscow Wi-Fi autologin)
 * Copyright © 2015 Dmitry Karikh <[email protected]>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package pw.thedrhax.mosmetro.activities;

import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import org.acra.ACRA;

import java.util.Map;

import pw.thedrhax.mosmetro.R;
import pw.thedrhax.mosmetro.preferences.LoginFormPreference;
import pw.thedrhax.mosmetro.services.ConnectionService;
import pw.thedrhax.mosmetro.updater.UpdateCheckTask;
import pw.thedrhax.util.Listener;
import pw.thedrhax.util.Logger;
import pw.thedrhax.util.PermissionUtils;
import pw.thedrhax.util.Randomizer;
import pw.thedrhax.util.Version;

public class SettingsActivity extends Activity {
    private SettingsFragment fragment;
    private Listener<Map<String,UpdateCheckTask.Branch>> branches;
    private SharedPreferences settings;

    public static class SettingsFragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.preferences);
        }
    }

    public static class NestedFragment extends PreferenceFragment {
        protected void setTitle(String title) {
            ActionBar bar = getActivity().getActionBar();
            if (bar != null) bar.setTitle(title);
        }

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setHasOptionsMenu(true);
        }

        @Override
        public void onPrepareOptionsMenu(Menu menu) {
            super.onPrepareOptionsMenu(menu);
            menu.clear();
        }
    }

    public static class BranchFragment extends NestedFragment {
        private Map<String,UpdateCheckTask.Branch> branches;

        public BranchFragment branches(@NonNull Map<String, UpdateCheckTask.Branch> branches) {
            this.branches = branches; return this;
        }

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setTitle(getString(R.string.pref_updater_branch));

            PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getActivity());
            setPreferenceScreen(screen);

            PreferenceCategory stable = new PreferenceCategory(getActivity());
            stable.setTitle(R.string.pref_updater_branch_stable);
            screen.addPreference(stable);

            PreferenceCategory experimental = new PreferenceCategory(getActivity());
            experimental.setTitle(R.string.pref_updater_branch_experimental);
            screen.addPreference(experimental);

            if (branches == null) return;
            final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getActivity());
            for (final UpdateCheckTask.Branch branch : branches.values()) {
                CheckBoxPreference pref = new CheckBoxPreference(getActivity()) {
                    @Override
                    protected void onBindView(View view) {
                        super.onBindView(view);

                        // Increase number of lines on Android 4.x
                        // Source: https://stackoverflow.com/a/2615650
                        TextView summary = (TextView) view.findViewById(android.R.id.summary);
                        summary.setMaxLines(15);
                    }
                };
                pref.setTitle(branch.name);
                pref.setSummary(branch.description);
                pref.setChecked(Version.getBranch().equals(branch.name));
                pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
                    @Override
                    public boolean onPreferenceClick(Preference preference) {
                        boolean same = Version.getBranch().equals(branch.name);
                        ((CheckBoxPreference)preference).setChecked(same);
                        if (!same) {
                            settings.edit().putInt("pref_updater_ignore", 0).apply();
                            branch.dialog().show();
                        }
                        getActivity().onBackPressed();
                        return true;
                    }
                });

                if (branch.stable) {
                    stable.addPreference(pref);
                } else {
                    experimental.addPreference(pref);
                }
            }
        }
    }

    public static class ConnectionSettingsFragment extends NestedFragment {
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            // Generate random User-Agent if it is unset
            new Randomizer(getActivity()).cached_useragent();

            setTitle(getString(R.string.pref_category_connection));
            addPreferencesFromResource(R.xml.pref_conn);

            PreferenceScreen screen = getPreferenceScreen();

            final CheckBoxPreference pref_mainet = (CheckBoxPreference)
                    screen.findPreference("pref_mainet");
            final LoginFormPreference pref_mainet_creds = (LoginFormPreference)
                    screen.findPreference("pref_mainet_credentials");
            pref_mainet_creds.setEnabled(pref_mainet.isChecked());
            pref_mainet.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
                @Override
                public boolean onPreferenceChange(Preference preference, Object newValue) {
                    pref_mainet_creds.setEnabled((Boolean) newValue);
                    return true;
                }
            });
        }
    }

    public static class NotificationSettingsFragment extends NestedFragment {
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setTitle(getString(R.string.pref_category_notifications));
            addPreferencesFromResource(R.xml.pref_notify);

            PreferenceScreen screen = getPreferenceScreen();

            // Link pref_notify_foreground and pref_notify_success_lock
            final CheckBoxPreference foreground = (CheckBoxPreference)
                    screen.findPreference("pref_notify_foreground");
            final CheckBoxPreference success = (CheckBoxPreference)
                    screen.findPreference("pref_notify_success");
            final CheckBoxPreference success_lock = (CheckBoxPreference)
                    screen.findPreference("pref_notify_success_lock");
            foreground.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
                @Override
                public boolean onPreferenceChange(Preference preference, Object newValue) {
                    success.setEnabled(!((Boolean) newValue));
                    success_lock.setEnabled(!((Boolean) newValue));
                    return true;
                }
            });
            foreground
                    .getOnPreferenceChangeListener()
                    .onPreferenceChange(foreground, foreground.isChecked());
        }
    }

    public static class DebugSettingsFragment extends NestedFragment {
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setTitle(getString(R.string.pref_debug));
            addPreferencesFromResource(R.xml.pref_debug);

            Preference.OnPreferenceChangeListener reload_logger = new Preference.OnPreferenceChangeListener() {
                @Override
                public boolean onPreferenceChange(Preference preference, Object newValue) {
                    PreferenceManager.getDefaultSharedPreferences(getActivity())
                            .edit()
                            .putBoolean(preference.getKey(), (Boolean) newValue)
                            .apply();
                    Logger.configure(getActivity());
                    return true;
                }
            };

            CheckBoxPreference pref_debug_logcat =
                    (CheckBoxPreference) getPreferenceScreen().findPreference("pref_debug_logcat");
            pref_debug_logcat.setOnPreferenceChangeListener(reload_logger);
        }
    }

    public static class AboutFragment extends NestedFragment {
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setTitle(getString(R.string.about));
            addPreferencesFromResource(R.xml.about);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.settings_activity, menu);
        return true;
    }

    private void donate_dialog() {
        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                ClipboardManager clipboard = (ClipboardManager)
                        getSystemService(Context.CLIPBOARD_SERVICE);
                ClipData clip;

                switch (i) {
                    case 0: // Yandex.Money
                        startActivity(new Intent(SettingsActivity.this, SafeViewActivity.class)
                                .putExtra("data", getString(R.string.donate_yandex_data))
                        );
                        break;

                    case 1: // Bitcoin
                        clip = ClipData.newPlainText("", getString(R.string.donate_bitcoin_data));
                        clipboard.setPrimaryClip(clip);

                        Toast.makeText(SettingsActivity.this,
                                R.string.clipboard_copy,
                                Toast.LENGTH_SHORT
                        ).show();
                        break;

                    case 2: // Ethereum
                        clip = ClipData.newPlainText("", getString(R.string.donate_ethereum_data));
                        clipboard.setPrimaryClip(clip);

                        Toast.makeText(SettingsActivity.this,
                                R.string.clipboard_copy,
                                Toast.LENGTH_SHORT
                        ).show();
                        break;

                    case 3: // Communities
                        replaceFragment("about", new AboutFragment());
                        break;
                }
            }
        };

        new AlertDialog.Builder(this)
                .setTitle(R.string.action_donate)
                .setItems(R.array.donate_options, listener)
                .show();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_donate:
                donate_dialog();
                return true;
            case android.R.id.home:
                onBackPressed();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void update_checker_setup() {
        // Force check
        final Preference pref_updater_check = fragment.findPreference("pref_updater_check");
        pref_updater_check.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @SuppressLint("StaticFieldLeak")
            @Override
            public boolean onPreferenceClick(Preference preference) {
                new UpdateCheckTask(SettingsActivity.this) {
                    @Override
                    protected void onPreExecute() {
                        super.onPreExecute();
                        pref_updater_check.setEnabled(false);
                    }

                    @Override
                    protected void onPostExecute(Void aVoid) {
                        super.onPostExecute(aVoid);
                        pref_updater_check.setEnabled(true);
                    }

                    @Override
                    public void result(@Nullable Map<String, Branch> result) {
                        branches.set(result);
                    }
                }.ignore(preference == null).force(preference != null).execute();
                return false;
            }
        });

        // Check for updates on start if enabled
        if (settings.getBoolean("pref_updater_enabled", true))
            pref_updater_check
                    .getOnPreferenceClickListener()
                    .onPreferenceClick(null);
    }

    @RequiresApi(23)
    private void energy_saving_setup() {
        final PermissionUtils pu = new PermissionUtils(this);

        AlertDialog.Builder dialog = new AlertDialog.Builder(this)
                .setTitle(R.string.dialog_battery_saving)
                .setMessage(R.string.dialog_battery_saving_summary)
                .setPositiveButton(R.string.permission_request, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        pu.requestBatterySavingIgnore();
                    }
                })
                .setNeutralButton(R.string.open_settings, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        pu.openBatterySavingSettings();
                    }
                })
                .setNegativeButton(R.string.ignore, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        settings.edit()
                                .putBoolean("pref_battery_saving_ignore", true)
                                .apply();
                        dialog.dismiss();
                    }
                });

        if (!settings.getBoolean("pref_battery_saving_ignore", false))
            if (!pu.isBatterySavingIgnored())
                dialog.show();
    }

    @RequiresApi(28)
    private void location_permission_setup() {
        final PermissionUtils pu = new PermissionUtils(this);

        AlertDialog.Builder dialog = new AlertDialog.Builder(this)
                .setTitle(R.string.location_permission)
                .setMessage(R.string.location_permission_saving)
                .setPositiveButton(R.string.permission_request, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        pu.requestCoarseLocation();
                    }
                })
                .setNeutralButton(R.string.open_settings, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        pu.openAppSettings();
                    }
                })
                .setNegativeButton(R.string.ignore, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        settings.edit()
                                .putBoolean("pref_location_ignore", true)
                                .apply();
                        dialog.dismiss();
                    }
                });

        if (!settings.getBoolean("pref_location_ignore", false))
            if (!pu.isCoarseLocationGranted())
                dialog.show();
    }

    private void replaceFragment(String id, Fragment fragment) {
        try {
            getFragmentManager()
                    .beginTransaction()
                    .replace(android.R.id.content, fragment)
                    .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                    .addToBackStack(id)
                    .commit();
        } catch (IllegalStateException ex) { // https://stackoverflow.com/q/7575921
            ACRA.getErrorReporter().handleException(ex);
        }
    }

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

        // Populate preferences
        final FragmentManager fmanager = getFragmentManager();
        fragment = new SettingsFragment();
        fmanager.beginTransaction()
                .replace(android.R.id.content, fragment)
                .commit();
        fmanager.executePendingTransactions();
        fmanager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
            @Override
            public void onBackStackChanged() {
                boolean root = fmanager.getBackStackEntryCount() == 0;

                ActionBar bar = getActionBar();
                if (bar != null) {
                    bar.setDisplayHomeAsUpEnabled(!root);

                    if (root) { // reset to defaults
                        bar.setTitle(R.string.app_name);
                    }
                }
            }
        });

        settings = PreferenceManager.getDefaultSharedPreferences(this);

        // Hide shortcut button on Android 8+ (issue #211)
        if (Build.VERSION.SDK_INT >= 26) {
            Preference pref_shortcut = fragment.findPreference("pref_shortcut");
            fragment.getPreferenceScreen().removePreference(pref_shortcut);
        }

        // Add version name and code
        Preference app_name = fragment.findPreference("app_name");
        app_name.setSummary(getString(R.string.version, Version.getFormattedVersion()));

        // Start/stop service on pref_autoconnect change
        final CheckBoxPreference pref_autoconnect =
                (CheckBoxPreference) fragment.findPreference("pref_autoconnect");
        pref_autoconnect.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
            @Override
            public boolean onPreferenceChange(Preference preference, Object o) {
                Context context = SettingsActivity.this;
                Intent service = new Intent(context, ConnectionService.class);
                if (pref_autoconnect.isChecked())
                    service.setAction("STOP");
                context.startService(service);
                return true;
            }
        });

        // Branch Selector
        Preference pref_updater_branch = fragment.findPreference("pref_updater_branch");
        pref_updater_branch.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                Map<String,UpdateCheckTask.Branch> branch_list = branches.get();
                if (branch_list != null) {
                    replaceFragment("branch", new BranchFragment().branches(branch_list));
                } else {
                    preference.setEnabled(false);
                }
                return true;
            }
        });

        branches = new Listener<Map<String,UpdateCheckTask.Branch>>(null) {
            @Override
            public void onChange(Map<String, UpdateCheckTask.Branch> new_value) {
                pref_updater_branch.setEnabled(new_value != null && new_value.size() > 0);
            }
        };

        // Connection Preferences
        Preference pref_conn = fragment.findPreference("pref_conn");
        pref_conn.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                replaceFragment("conn", new ConnectionSettingsFragment());
                return true;
            }
        });

        // Notification Preferences
        Preference pref_notify = fragment.findPreference("pref_notify");
        pref_notify.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                replaceFragment("notify", new NotificationSettingsFragment());
                return true;
            }
        });

        // Debug
        Preference pref_debug = fragment.findPreference("pref_debug");
        pref_debug.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                replaceFragment("debug", new DebugSettingsFragment());
                return true;
            }
        });

        // About
        Preference pref_about = fragment.findPreference("pref_about");
        pref_about.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                replaceFragment("about", new AboutFragment());
                return true;
            }
        });

        update_checker_setup();
        if (Build.VERSION.SDK_INT >= 23)
            energy_saving_setup();
        if (Build.VERSION.SDK_INT >= 28)
            location_permission_setup();
    }
}