package com.gianlu.aria2app;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.pm.ShortcutInfoCompat;
import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.core.graphics.drawable.IconCompat;
import androidx.documentfile.provider.DocumentFile;

import com.gianlu.aria2app.downloader.FetchHelper;
import com.gianlu.aria2app.profiles.ProfilesManager;
import com.gianlu.aria2app.services.NotificationService;
import com.gianlu.commonutils.CommonUtils;
import com.gianlu.commonutils.preferences.BasePreferenceActivity;
import com.gianlu.commonutils.preferences.BasePreferenceFragment;
import com.gianlu.commonutils.preferences.MaterialAboutPreferenceItem;
import com.gianlu.commonutils.preferences.Prefs;
import com.gianlu.commonutils.ui.Toaster;
import com.yarolegovich.mp.AbsMaterialTextValuePreference;
import com.yarolegovich.mp.MaterialCheckboxPreference;
import com.yarolegovich.mp.MaterialMultiChoicePreference;
import com.yarolegovich.mp.MaterialSeekBarPreference;
import com.yarolegovich.mp.MaterialStandardPreference;

import org.json.JSONArray;
import org.json.JSONException;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;

public class PreferenceActivity extends BasePreferenceActivity {
    @NonNull
    @Override
    protected List<MaterialAboutPreferenceItem> getPreferencesItems() {
        return Arrays.asList(new MaterialAboutPreferenceItem(R.string.general, R.drawable.baseline_settings_24, GeneralFragment.class),
                new MaterialAboutPreferenceItem(R.string.profiles, R.drawable.baseline_supervisor_account_24, ProfilesFragment.class),
                new MaterialAboutPreferenceItem(R.string.directDownload, R.drawable.baseline_cloud_download_24, DirectDownloadFragment.class),
                new MaterialAboutPreferenceItem(R.string.notifications, R.drawable.baseline_sms_24, NotificationsFragment.class));
    }

    @Override
    protected int getAppIconRes() {
        return R.drawable.ic_launcher;
    }

    @Override
    protected boolean hasTutorial() {
        return true;
    }

    @Nullable
    @Override
    protected String getOpenSourceUrl() {
        return "https://github.com/devgianlu/Aria2App";
    }

    @Override
    protected boolean disableOtherDonationsOnGooglePlay() {
        return true;
    }

    public static class GeneralFragment extends BasePreferenceFragment {

        @Override
        protected void buildPreferences(@NonNull Context context) {
            MaterialCheckboxPreference nightMode = new MaterialCheckboxPreference.Builder(context)
                    .defaultValue(PK.NIGHT_MODE.fallback())
                    .key(PK.NIGHT_MODE.key())
                    .build();
            nightMode.setTitle(R.string.prefs_nightMode);
            nightMode.setSummary(R.string.prefs_nightMode_summary);
            nightMode.setIcon(R.drawable.baseline_opacity_24);
            addPreference(nightMode);

            MaterialCheckboxPreference hideMetadata = new MaterialCheckboxPreference.Builder(context)
                    .defaultValue(PK.A2_HIDE_METADATA.fallback())
                    .key(PK.A2_HIDE_METADATA.key())
                    .build();
            hideMetadata.setTitle(R.string.prefs_hideMetadata);
            hideMetadata.setSummary(R.string.prefs_hideMetadata_summary);
            hideMetadata.setIcon(R.drawable.baseline_link_24);
            addPreference(hideMetadata);

            MaterialSeekBarPreference updateRate = new MaterialSeekBarPreference.Builder(context)
                    .minValue(1).maxValue(10).showValue(true)
                    .key(PK.A2_UPDATE_INTERVAL.key())
                    .defaultValue(PK.A2_UPDATE_INTERVAL.fallback())
                    .build();
            updateRate.setTitle(R.string.prefs_updateRate);
            updateRate.setSummary(R.string.prefs_updateRate_summary);
            updateRate.setIcon(R.drawable.baseline_update_24);
            addPreference(updateRate);

            MaterialSeekBarPreference networkTimeout = new MaterialSeekBarPreference.Builder(context)
                    .minValue(1).maxValue(60).showValue(true)
                    .key(PK.A2_NETWORK_TIMEOUT.key())
                    .defaultValue(PK.A2_NETWORK_TIMEOUT.fallback())
                    .build();
            networkTimeout.setTitle(R.string.prefs_networkTimeout);
            networkTimeout.setSummary(R.string.prefs_networkTimeout_summary);
            networkTimeout.setIcon(R.drawable.baseline_network_check_24);
            addPreference(networkTimeout);

            MaterialMultiChoicePreference customDownloadInfo = new MaterialMultiChoicePreference.Builder(context)
                    .entryValues(CustomDownloadInfo.Info.stringValues())
                    .entries(CustomDownloadInfo.Info.formalValues(context))
                    .defaultValue(CustomDownloadInfo.Info.DOWNLOAD_SPEED.name(), CustomDownloadInfo.Info.REMAINING_TIME.name())
                    .showValueMode(AbsMaterialTextValuePreference.SHOW_ON_BOTTOM)
                    .key(PK.A2_CUSTOM_INFO.key())
                    .build();
            customDownloadInfo.setTitle(R.string.prefs_downloadDisplayInfo);
            customDownloadInfo.setSummary(R.string.prefs_downloadDisplayInfo_summary);
            customDownloadInfo.setIcon(R.drawable.baseline_info_outline_24);
            addPreference(customDownloadInfo);

            MaterialCheckboxPreference versionCheck = new MaterialCheckboxPreference.Builder(context)
                    .key(PK.A2_CHECK_VERSION.key())
                    .defaultValue(PK.A2_CHECK_VERSION.fallback())
                    .build();
            versionCheck.setTitle(R.string.prefs_versionCheck);
            versionCheck.setSummary(R.string.prefs_versionCheck_summary);
            versionCheck.setIcon(R.drawable.baseline_verified_user_24);
            addPreference(versionCheck);

            MaterialCheckboxPreference bestTrackers = new MaterialCheckboxPreference.Builder(context)
                    .key(PK.A2_ADD_BEST_TRACKERS.key())
                    .defaultValue(PK.A2_ADD_BEST_TRACKERS.fallback())
                    .build();
            bestTrackers.setTitle(R.string.prefs_addBestTrackers);
            bestTrackers.setSummary(R.string.prefs_addBestTrackers_summary);
            bestTrackers.setIcon(R.drawable.baseline_track_changes_24);
            addPreference(bestTrackers);

            MaterialCheckboxPreference skipWebViewDialog = new MaterialCheckboxPreference.Builder(context)
                    .key(PK.A2_SKIP_WEBVIEW_DIALOG.key())
                    .defaultValue(PK.A2_SKIP_WEBVIEW_DIALOG.fallback())
                    .build();
            skipWebViewDialog.setTitle(R.string.prefs_skipWebViewDialog);
            skipWebViewDialog.setSummary(R.string.prefs_skipWebViewDialog_summary);
            // skipWebViewDialog.setIcon(R.drawable.baseline_track_changes_24);
            addPreference(skipWebViewDialog);

            if (ShortcutManagerCompat.isRequestPinShortcutSupported(context)) {
                MaterialStandardPreference webviewShortcut = new MaterialStandardPreference(context);
                webviewShortcut.setTitle(R.string.addWebViewShortcutToHomePage);
                webviewShortcut.setSummary(R.string.addWebViewShortcutToHomePage_summary);
                webviewShortcut.setIcon(R.drawable.baseline_language_24);
                addPreference(webviewShortcut);

                webviewShortcut.setOnClickListener(v -> {
                    ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(context, "#1")
                            .setIntent(new Intent(context, LoadingActivity.class)
                                    .setAction(LoadingActivity.SHORTCUT_WEB_VIEW))
                            .setShortLabel(getString(R.string.webView) + " - " + getString(R.string.app_name))
                            .setIcon(IconCompat.createWithResource(context, R.drawable.baseline_language_colored_24))
                            .build();
                    ShortcutManagerCompat.requestPinShortcut(context, shortcutInfo, null);
                });
            }
        }

        @Override
        public int getTitleRes() {
            return R.string.general;
        }
    }

    public static class ProfilesFragment extends BasePreferenceFragment {
        private static final int IMPORT_PROFILES_CODE = 7;
        private static final String TAG = ProfilesFragment.class.getSimpleName();

        @Override
        protected void buildPreferences(@NonNull Context context) {
            MaterialStandardPreference importProfiles = new MaterialStandardPreference(context);
            importProfiles.setTitle(R.string.importProfiles);
            importProfiles.setSummary(R.string.importProfiles_summary);
            addPreference(importProfiles);

            importProfiles.setOnClickListener(v -> {
                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
                intent.addCategory(Intent.CATEGORY_OPENABLE);
                intent.setType("*/*");

                try {
                    startActivityForResult(Intent.createChooser(intent, "Select a file"), IMPORT_PROFILES_CODE);
                } catch (ActivityNotFoundException ex) {
                    showToast(Toaster.build().message(R.string.noFilemanager));
                }
            });

            MaterialStandardPreference exportProfiles = new MaterialStandardPreference(context);
            exportProfiles.setTitle(R.string.exportProfiles);
            exportProfiles.setSummary(R.string.exportProfiles_summary);
            addPreference(exportProfiles);

            exportProfiles.setOnClickListener(v -> doExport());
        }

        private void doExport() {
            try {
                JSONArray json = ProfilesManager.get(requireContext()).exportAllProfiles();

                File file = new File(requireContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "aria2app-profiles-" + CommonUtils.randomString(5) + ".json");
                try (FileOutputStream out = new FileOutputStream(file)) {
                    out.write(json.toString().getBytes());
                }

                showToast(Toaster.build().message(R.string.profilesExportedSuccessfully, file.getAbsolutePath()));
            } catch (JSONException | IOException ex) {
                Log.e(TAG, "Failed exporting profiles.", ex);
                showToast(Toaster.build().message(R.string.failedExportingProfiles));
            }
        }

        private void doImport(@NonNull Uri uri) {
            try {
                ByteArrayOutputStream bout = new ByteArrayOutputStream();
                try (InputStream in = requireContext().getContentResolver().openInputStream(uri)) {
                    if (in == null) return;

                    byte[] buffer = new byte[1024];
                    int count;
                    while ((count = in.read(buffer)) != -1)
                        bout.write(buffer, 0, count);
                }

                ProfilesManager.get(requireContext()).importProfiles(new JSONArray(new String(bout.toByteArray())));

                showToast(Toaster.build().message(R.string.profilesImportedSuccessfully));
            } catch (JSONException | IOException ex) {
                Log.e(TAG, "Failed importing profiles.", ex);
                showToast(Toaster.build().message(R.string.failedImportingProfiles));
            }
        }

        @Override
        public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            if (requestCode == IMPORT_PROFILES_CODE) {
                if (resultCode == RESULT_OK) {
                    if (getContext() == null || data == null || data.getData() == null)
                        return;

                    doImport(data.getData());
                }
            } else {
                super.onActivityResult(requestCode, resultCode, data);
            }
        }

        @Override
        public int getTitleRes() {
            return R.string.profiles;
        }
    }

    public static class DirectDownloadFragment extends BasePreferenceFragment {
        private static final int DOWNLOAD_PATH_CODE = 34;

        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == DOWNLOAD_PATH_CODE) {
                if (resultCode == RESULT_OK && isAdded() && data.getData() != null) {
                    DocumentFile file = DocumentFile.fromTreeUri(requireContext(), data.getData());
                    if (file != null)
                        Prefs.putString(PK.DD_DOWNLOAD_PATH, file.getUri().toString());
                }

                return;
            }

            super.onActivityResult(requestCode, resultCode, data);
        }

        @Override
        protected void buildPreferences(@NonNull Context context) {
            MaterialCheckboxPreference external = new MaterialCheckboxPreference.Builder(context)
                    .key(PK.DD_USE_EXTERNAL.key())
                    .defaultValue(PK.DD_USE_EXTERNAL.fallback())
                    .build();
            external.setTitle(R.string.prefs_ddUseExternal);
            external.setSummary(R.string.prefs_ddUseExternal_summary);
            external.setIcon(R.drawable.baseline_share_24);
            addPreference(external);

            MaterialStandardPreference downloadPath = new MaterialStandardPreference.Builder(context)
                    .key(PK.DD_DOWNLOAD_PATH.key())
                    .defaultValue(PK.DD_DOWNLOAD_PATH.fallback())
                    .build();
            downloadPath.setTitle(R.string.prefs_ddDownloadPath);
            downloadPath.setSummary(R.string.prefs_ddDownloadPath_summary);
            downloadPath.setIcon(R.drawable.baseline_folder_24);
            downloadPath.addPreferenceClickListener(v -> {
                try {
                    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
                    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
                    startActivityForResult(intent, DOWNLOAD_PATH_CODE);
                } catch (ActivityNotFoundException ex) {
                    showToast(Toaster.build().message(R.string.noFilemanager));
                }
            });
            addPreference(downloadPath);

            MaterialSeekBarPreference concurrentDownloads = new MaterialSeekBarPreference.Builder(context)
                    .minValue(1).maxValue(10).showValue(true)
                    .key(PK.DD_MAX_SIMULTANEOUS_DOWNLOADS.key())
                    .defaultValue(PK.DD_MAX_SIMULTANEOUS_DOWNLOADS.fallback())
                    .build();
            concurrentDownloads.setTitle(R.string.prefs_ddMaxSimultaneousDownloads);
            concurrentDownloads.setSummary(R.string.prefs_ddMaxSimultaneousDownloads_summary);
            concurrentDownloads.setIcon(R.drawable.baseline_download_24);
            addPreference(concurrentDownloads);

            MaterialCheckboxPreference resume = new MaterialCheckboxPreference.Builder(context)
                    .key(PK.DD_RESUME.key())
                    .defaultValue(PK.DD_RESUME.fallback())
                    .build();
            resume.setTitle(R.string.prefs_ddResume);
            resume.setSummary(R.string.prefs_ddResume_summary);
            resume.setIcon(R.drawable.baseline_pause_24);
            addPreference(resume);

            addController(external, false, downloadPath, concurrentDownloads, resume);
        }

        @Override
        public void onDestroy() {
            super.onDestroy();

            FetchHelper.invalidate();
        }

        @Override
        public int getTitleRes() {
            return R.string.directDownload;
        }
    }

    public static class NotificationsFragment extends BasePreferenceFragment {

        @Override
        protected void buildPreferences(@NonNull Context context) {
            MaterialCheckboxPreference enable = new MaterialCheckboxPreference.Builder(context)
                    .key(PK.A2_ENABLE_NOTIFS.key())
                    .defaultValue(PK.A2_ENABLE_NOTIFS.fallback())
                    .build();
            enable.setTitle(R.string.prefs_enableNotifications);
            enable.setSummary(R.string.prefs_enableNotifications_summary);
            enable.setIcon(R.drawable.baseline_notifications_24);
            addPreference(enable);

            MaterialMultiChoicePreference types = new MaterialMultiChoicePreference.Builder(context)
                    .entryValues(NotificationService.EventType.prefsValues())
                    .entries(NotificationService.EventType.formalValues(context))
                    .showValueMode(AbsMaterialTextValuePreference.SHOW_ON_BOTTOM)
                    .key(PK.A2_SELECTED_NOTIFS_TYPE.key())
                    .defaultValue(PK.A2_SELECTED_NOTIFS_TYPE.fallback())
                    .build();
            types.setTitle(R.string.prefs_notificationType);
            types.setSummary(R.string.prefs_notificationType_summary);
            types.setIcon(R.drawable.baseline_more_24);
            addPreference(types);

            MaterialCheckboxPreference startAtBoot = new MaterialCheckboxPreference.Builder(context)
                    .key(PK.A2_NOTIFS_AT_BOOT.key())
                    .defaultValue(PK.A2_NOTIFS_AT_BOOT.fallback())
                    .build();
            startAtBoot.setTitle(R.string.prefs_enableNotificationsAtBoot);
            startAtBoot.setSummary(R.string.prefs_enableNotificationsAtBoot_summary);
            startAtBoot.setIcon(R.drawable.baseline_android_24);
            addPreference(startAtBoot);

            addController(enable, true, startAtBoot, types);
        }

        @Override
        public int getTitleRes() {
            return R.string.notifications;
        }
    }
}