/*
 * Copyright (c) 2016 - 2019 Rui Zhao <[email protected]>
 *
 * This file is part of Easer.
 *
 * Easer 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.
 *
 * Easer 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 Easer.  If not, see <http://www.gnu.org/licenses/>.
 */

package ryey.easer.core.ui.setting;

import android.Manifest;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.TwoStatePreference;
import android.view.MenuItem;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.orhanobut.logger.Logger;
import com.zeugmasolutions.localehelper.LocaleHelper;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;

import ryey.easer.BuildConfig;
import ryey.easer.R;
import ryey.easer.commons.ui.CommonBaseActivity;
import ryey.easer.core.BootUpReceiver;
import ryey.easer.core.EHService;
import ryey.easer.core.UpgradeCompleteReceiver;
import ryey.easer.core.data.Helper;
import ryey.easer.core.data.InvalidExportedDataException;
import ryey.easer.core.data.storage.StorageHelper;

public class SettingsActivity extends CommonBaseActivity implements SharedPreferences.OnSharedPreferenceChangeListener {

    private static final String BS_NAME_PLUGIN_ENABLED = "bs_plugin_enabled";

    private static final String ARG_PAGE = "ryey.easer.core.ui.setting.ARG.PAGE";
    private static final int PAGE_DEFAULT = -1;
    private static final int PAGE_SKILL = 1;

    public static void callSkillSettings(Activity activity) {
        Intent intent = new Intent(activity, SettingsActivity.class);
        intent.putExtra(ARG_PAGE, PAGE_SKILL);
        activity.startActivity(intent);
    }

    private static boolean hasPermission(Context context, String permission) {
        if (ContextCompat.checkSelfPermission(context, permission)
                != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(context, String.format(
                    context.getString(R.string.prompt_prevented_for_permission), permission),
                    Toast.LENGTH_LONG).show();
            return false;
        } else
            return true;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setTitle(R.string.title_setting);
        Bundle args = getIntent().getExtras();
        int startPage = PAGE_DEFAULT;
        if (args != null) {
            startPage = args.getInt(ARG_PAGE, PAGE_DEFAULT);
        }
        switch (startPage) {
            case PAGE_SKILL:
                setSkillFragment(getFragmentManager(), false);
                break;
            default:
                getFragmentManager().beginTransaction()
                        .replace(android.R.id.content, new SettingsFragment())
                        .commit();
        }
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

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

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        if (key.equals(getString(R.string.key_pref_autostart))) {
            ComponentName componentName = new ComponentName(this, BootUpReceiver.class);
            PackageManager pm = getPackageManager();
            if (sharedPreferences.getBoolean(key, false)) {
                pm.setComponentEnabledSetting(componentName,
                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                        PackageManager.DONT_KILL_APP);
            } else {
                pm.setComponentEnabledSetting(componentName,
                        PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                        PackageManager.DONT_KILL_APP);
            }
        } else if (key.equals(getString(R.string.key_pref_restart_after_upgrade))) {
            ComponentName componentName = new ComponentName(this, UpgradeCompleteReceiver.class);
            PackageManager pm = getPackageManager();
            if (sharedPreferences.getBoolean(key, false)) {
                pm.setComponentEnabledSetting(componentName,
                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                        PackageManager.DONT_KILL_APP);
            } else {
                pm.setComponentEnabledSetting(componentName,
                        PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                        PackageManager.DONT_KILL_APP);
            }
        } else if (key.equals(getString(R.string.key_pref_use_root))) {
            if (sharedPreferences.getBoolean(key, false)) {
                try {
                    Process p = Runtime.getRuntime().exec("su");
                } catch (IOException e) {
                    e.printStackTrace();
                    sharedPreferences.edit().putBoolean(key, false).apply();
                }
            }
        }
    }

    static void setSkillFragment(FragmentManager fragmentManager, boolean addToBackStack) {
        SkillSettingsPreferenceFragment fragment = new SkillSettingsPreferenceFragment();
        FragmentTransaction transaction = fragmentManager.beginTransaction()
                .replace(android.R.id.content, fragment);
        if (addToBackStack) {
            transaction.addToBackStack(BS_NAME_PLUGIN_ENABLED);
        }
        transaction.commit();
    }

    public static class SettingsFragment extends PreferenceFragment {

        final static int REQCODE_PICK_FILE = 10;
        final static int REQCODE_PICK_FILE_EXPORT = 15;
        final static int REQCODE_PERM_EXPORT = 11;
        final static int REQCODE_PERM_IMPORT = 12;
        final static int REQCODE_PERM_STORAGE = 1;

        private final static String FILETYPE_EXPORT_DATA = "application/zip";

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.preferences);

            try {
                PackageInfo pInfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0);
                String version = pInfo.versionName;
                Preference pref_version = findPreference(getString(R.string.key_pref_version));
                pref_version.setSummary(version);
            } catch (PackageManager.NameNotFoundException e) {
                Logger.e(e, "Unable to get app version");
            }

            Preference pref_export = findPreference(getString(R.string.key_pref_export));
            pref_export.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
                public boolean onPreferenceClick(Preference preference) {
                    if (!hasPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                        ActivityCompat.requestPermissions(getActivity(),
                                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                REQCODE_PERM_EXPORT);
                    } else {
                        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
                            export_data(getActivity());
                        } else {
                            Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
                            intent.addCategory(Intent.CATEGORY_OPENABLE);
                            intent.setType(FILETYPE_EXPORT_DATA);
                            intent.putExtra(Intent.EXTRA_TITLE, exportFileName());
                            startActivityForResult(intent, REQCODE_PICK_FILE_EXPORT);
                        }
                    }
                    return true;
                }
            });

            Preference pref_import = findPreference(getString(R.string.key_pref_import));
            pref_import.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
                @Override
                public boolean onPreferenceClick(Preference preference) {
                    if (!hasPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                            ActivityCompat.requestPermissions(getActivity(),
                                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                                    REQCODE_PERM_IMPORT);
                            return false;
                        }
                    } else {
                        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
                        intent.setType("application/zip");
                        startActivityForResult(intent, REQCODE_PICK_FILE);
                    }
                    return true;
                }
            });

            Preference pref_logging = findPreference(getString(R.string.key_pref_logging));
            pref_logging.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
                @Override
                public boolean onPreferenceChange(Preference preference, Object newValue) {
                    if ((Boolean) newValue) {
                        if (!hasPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                            Logger.i("Permission <%s> not granted. Requesting...",
                                    Manifest.permission.WRITE_EXTERNAL_STORAGE);
                            ActivityCompat.requestPermissions(getActivity(),
                                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                    REQCODE_PERM_STORAGE);
                            return false;
                        }
                    }
                    return true;
                }
            });

            findPreference(getString(R.string.key_pref_cooldown))
                    .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
                        @Override
                        public boolean onPreferenceChange(Preference preference, Object newValue) {
                            if (BuildConfig.DEBUG && !(newValue instanceof String))
                                throw new AssertionError();
                            String interval_str = (String) newValue;
                            try {
                                int interval = Integer.parseInt(interval_str);
                                if (interval < 0)
                                    throw new NumberFormatException();
                                return true;
                            } catch (NumberFormatException e) {
                                Toast.makeText(getActivity(),
                                        R.string.cooldown_time_illformed, Toast.LENGTH_SHORT)
                                        .show();
                                return false;
                            }
                        }
                    });

            findPreference(getString(R.string.key_pref_plugins))
                    .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
                @Override
                public boolean onPreferenceClick(Preference preference) {
                    setSkillFragment(getFragmentManager(), true);
                    return true;
                }
            });

            findPreference(getString(R.string.key_pref_convert_data))
                    .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
                @Override
                public boolean onPreferenceClick(Preference preference) {
                    if (!StorageHelper.convertToNewData(getActivity())) {
                        Toast.makeText(getActivity(), R.string.message_convert_data_error, Toast.LENGTH_LONG).show();
                    }
                    return true;
                }
            });

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                for (int key_id : new int[]{
                        R.string.key_pref_show_notification,
                        R.string.key_pref_foreground}) {
                    Preference pref = findPreference(getString(key_id));
                    pref.setEnabled(false);
                    ((TwoStatePreference) pref).setChecked(true);
                }
            }

            ((ListPreference) findPreference(getString(R.string.key_pref_locale_lang)))
                    .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
                        @Override
                        public boolean onPreferenceChange(Preference preference, Object newValue) {
                            String locale_str = (String) newValue;
                            Locale locale;
                            if ("_".equals(locale_str)) {
                                locale = Resources.getSystem().getConfiguration().locale;
                            } else if ("zh".equals(locale_str)) {
                                locale = Locale.CHINESE;
                            } else {
                                locale = new Locale(locale_str);
                            }
                            Logger.d("Locale changing to %s, based on %s", locale, locale_str);
                            Context context;
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                context = getContext();
                            } else {
                                context = getActivity();
                            }
                            LocaleHelper.INSTANCE.setLocale(context, locale);
                            return true;
                        }
                    });

        }

        @Override
        public void onResume() {
            super.onResume();
            getPreferenceScreen().getSharedPreferences()
                    .registerOnSharedPreferenceChangeListener((SettingsActivity) getActivity());
        }

        @Override
        public void onPause() {
            super.onPause();
            getPreferenceScreen().getSharedPreferences()
                    .unregisterOnSharedPreferenceChangeListener((SettingsActivity) getActivity());
        }

        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (resultCode == RESULT_OK) {
                if (requestCode == REQCODE_PICK_FILE) {
                    Uri uri = data.getData();
                    try {
                        Helper.import_data(getActivity(), uri);
                        EHService.reload(getActivity());
                    } catch (IOException e) {
                        Logger.e(e, "IOException caught when importing data");
                        e.printStackTrace();
                    } catch (InvalidExportedDataException e) {
                        Toast.makeText(getActivity(),
                                R.string.message_importing_invalid_data,
                                Toast.LENGTH_LONG)
                                .show();
                        e.printStackTrace();
                    }
                } else if (requestCode == REQCODE_PICK_FILE_EXPORT) {
                    Uri uri = data.getData();
                    try {
                        Helper.export_data(getActivity(), uri);
                    } catch (IOException e) {
                        Logger.e(e, "IOException caught when exporting data");
                        e.printStackTrace();
                    }
                }
            }
        }

        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            switch (requestCode) {
                case REQCODE_PERM_STORAGE:
                case REQCODE_PERM_EXPORT:
                case REQCODE_PERM_IMPORT:
                    if (grantResults.length == 0) {
                        Logger.wtf("Request permission result with ZERO length!!!");
                        return;
                    }
                    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        Logger.i("Request for permission <%s> granted", permissions[0]);
                    } else {
                        Logger.i("Request for permission <%s> denied", permissions[0]);
                    }
                    break;
            }
        }

        private static String exportFileName() {
            Calendar calendar = Calendar.getInstance();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd.hh:mm:ss", Locale.US);
            String time_str = sdf.format(calendar.getTime());
            return String.format("Easer.%s.zip", time_str);
        }

        private static void export_data(Context context) {
            try {
                File sdCard = Environment.getExternalStorageDirectory();
                File dest = new File(sdCard, exportFileName());
                Logger.v("Export destination: %s", dest);
                Helper.export_data(context, dest);
                Toast.makeText(context,
                        String.format(context.getString(R.string.template_export), dest.getName()),
                        Toast.LENGTH_SHORT).show();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}