package nodomain.freeyourgadget.gadgetbridge.devices.garmin;

import static nodomain.freeyourgadget.gadgetbridge.util.GB.toast;

import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Parcel;
import android.widget.Toast;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.documentfile.provider.DocumentFile;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;

import com.google.android.material.dialog.MaterialAlertDialogBuilder;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.agps.GarminAgpsStatus;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;

public class GarminSettingsCustomizer implements DeviceSpecificSettingsCustomizer {
    private static final Logger LOG = LoggerFactory.getLogger(GarminSettingsCustomizer.class);

    private final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());

    @Override
    public void onPreferenceChange(final Preference preference, final DeviceSpecificSettingsHandler handler) {
    }

    @Override
    public void customizeSettings(final DeviceSpecificSettingsHandler handler, final Prefs prefs, final String rootKey) {
        final Preference realtimeSettings = handler.findPreference(GarminPreferences.PREF_GARMIN_REALTIME_SETTINGS);
        if (realtimeSettings != null) {
            realtimeSettings.setOnPreferenceClickListener(preference -> {
                final Intent intent = new Intent(handler.getContext(), GarminRealtimeSettingsActivity.class);
                intent.putExtra(GBDevice.EXTRA_DEVICE, handler.getDevice());
                handler.getContext().startActivity(intent);
                return true;
            });
        }

        final PreferenceCategory prefAgpsHeader = handler.findPreference(DeviceSettingsPreferenceConst.PREF_HEADER_AGPS);
        if (prefAgpsHeader != null) {
            final List<String> urls = prefs.getList(GarminPreferences.PREF_AGPS_KNOWN_URLS, Collections.emptyList(), "\n");
            if (urls.isEmpty()) {
                return;
            }

            final String currentFolder = prefs.getString(GarminPreferences.PREF_GARMIN_AGPS_FOLDER, "");

            final Preference prefFolder = handler.findPreference(GarminPreferences.PREF_GARMIN_AGPS_FOLDER);
            final ActivityResultLauncher<Uri> agpsFolderChooser = handler.registerForActivityResult(
                    new ActivityResultContracts.OpenDocumentTree(),
                    localUri -> {
                        LOG.info("Garmin agps folder: {}", localUri);
                        if (localUri != null) {
                            handler.getContext().getContentResolver().takePersistableUriPermission(localUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
                            prefs.getPreferences().edit()
                                    .putString(GarminPreferences.PREF_GARMIN_AGPS_FOLDER, localUri.toString())
                                    .apply();
                            prefFolder.setSummary(localUri.toString());

                            for (final String url : urls) {
                                updateAgpsStatus(handler, prefs, url);
                            }
                        }
                    }
            );
            prefFolder.setOnPreferenceClickListener(preference -> {
                agpsFolderChooser.launch(null);
                return true;
            });
            prefFolder.setSummary(currentFolder);
            prefAgpsHeader.addPreference(prefFolder);

            int i = 0;
            for (final String url : urls) {
                i++;

                final Preference prefHeader = new PreferenceCategory(handler.getContext());
                prefHeader.setKey("pref_agps_url_header_" + i);
                prefHeader.setIconSpaceReserved(false);
                prefHeader.setTitle(handler.getContext().getString(R.string.garmin_agps_url_i, i));
                prefAgpsHeader.addPreference(prefHeader);

                final Preference prefUrl = new Preference(handler.getContext());
                prefUrl.setOnPreferenceClickListener(preference -> {
                    final ClipboardManager clipboard = (ClipboardManager) handler.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
                    final ClipData clip = ClipData.newPlainText(handler.getContext().getString(R.string.url), url);
                    clipboard.setPrimaryClip(clip);
                    toast(handler.getContext(), handler.getContext().getString(R.string.copied_to_clipboard), Toast.LENGTH_SHORT, GB.INFO);
                    return true;
                });
                prefUrl.setKey("pref_garmin_agps_url_" + i);
                prefUrl.setIcon(R.drawable.ic_link);
                prefUrl.setTitle(R.string.url);
                prefUrl.setSummary(url);
                prefAgpsHeader.addPreference(prefUrl);

                final Preference prefLocalFile = new Preference(handler.getContext());
                prefLocalFile.setOnPreferenceClickListener(preference -> {
                    selectAgpsFile(handler, prefs, url, prefLocalFile);
                    return true;
                });
                prefLocalFile.setKey(GarminPreferences.agpsFilename(url));
                prefLocalFile.setIcon(R.drawable.ic_file_open);
                prefLocalFile.setTitle(R.string.garmin_agps_local_file);
                prefLocalFile.setSummary(prefs.getString(GarminPreferences.agpsFilename(url), ""));
                prefAgpsHeader.addPreference(prefLocalFile);

                final Preference prefStatus = new Preference(handler.getContext());
                prefStatus.setKey(GarminPreferences.agpsStatus(url));
                prefStatus.setIcon(R.drawable.ic_health);
                prefStatus.setTitle(R.string.status);
                prefAgpsHeader.addPreference(prefStatus);
                updateAgpsStatus(handler, prefs, url);

                final Preference prefUpdateTime = new Preference(handler.getContext());
                prefUpdateTime.setKey(GarminPreferences.agpsUpdateTime(url));
                prefUpdateTime.setIcon(R.drawable.ic_calendar_today);
                prefUpdateTime.setTitle(R.string.pref_agps_update_time);
                final long ts = prefs.getLong(GarminPreferences.agpsUpdateTime(url), 0L);
                if (ts > 0) {
                    prefUpdateTime.setSummary(SDF.format(new Date(ts)));
                } else {
                    prefUpdateTime.setSummary(handler.getContext().getString(R.string.unknown));
                }
                prefAgpsHeader.addPreference(prefUpdateTime);
            }
        }
    }

    private void selectAgpsFile(final DeviceSpecificSettingsHandler handler, final Prefs prefs, final String url, final Preference prefLocalFile) {
        final String currentFolder = prefs.getString(GarminPreferences.PREF_GARMIN_AGPS_FOLDER, "");

        final String folderUri = prefs.getString(GarminPreferences.PREF_GARMIN_AGPS_FOLDER, "");
        if (folderUri.isEmpty()) {
            GB.toast(handler.getContext().getString(R.string.no_folder_selected), Toast.LENGTH_SHORT, GB.INFO);
            return;
        }

        final DocumentFile folder = DocumentFile.fromTreeUri(handler.getContext(), Uri.parse(currentFolder));
        if (folder == null || folder.listFiles().length == 0) {
            GB.toast(handler.getContext().getString(R.string.folder_is_empty), Toast.LENGTH_SHORT, GB.INFO);
            return;
        }

        final DocumentFile[] documentFiles = folder.listFiles();
        final String[] files = new String[documentFiles.length + 1];
        files[0] = handler.getContext().getString(R.string.none);
        final String selectedFile = prefs.getString(GarminPreferences.agpsFilename(url), "");
        int checkedItem = 0;
        for (int j = 0; j < documentFiles.length; j++) {
            files[j + 1] = documentFiles[j].getName();
            if (selectedFile.equals(files[j + 1])) {
                checkedItem = j + 1;
            }
        }

        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(handler.getContext());
        builder.setTitle(R.string.garmin_agps_local_file);

        final AtomicInteger selectedIdx = new AtomicInteger(0);
        builder.setSingleChoiceItems(files, checkedItem, (dialog, which) -> {
            selectedIdx.set(which);
        });
        builder.setPositiveButton(android.R.string.ok, (dialog, which) -> {
            final String selectedFilename = selectedIdx.get() > 0 ? files[selectedIdx.get()] : null;
            prefs.getPreferences().edit()
                    .putString(GarminPreferences.agpsFilename(url), selectedFilename)
                    .apply();
            prefLocalFile.setSummary(selectedFilename);
            updateAgpsStatus(handler, prefs, url);
        });
        builder.setNegativeButton(android.R.string.cancel, null);
        builder.create().show();
    }

    private void updateAgpsStatus(final DeviceSpecificSettingsHandler handler, final Prefs prefs, final String url) {
        final Preference prefStatus = handler.findPreference(GarminPreferences.agpsStatus(url));

        final String filename = prefs.getString(GarminPreferences.agpsFilename(url), "");
        if (filename.isEmpty()) {
            prefStatus.setSummary("");
            return;
        }
        final String folderUri = prefs.getString(GarminPreferences.PREF_GARMIN_AGPS_FOLDER, "");
        if (folderUri.isEmpty()) {
            prefStatus.setSummary("");
            return;
        }
        final DocumentFile folder = DocumentFile.fromTreeUri(handler.getContext(), Uri.parse(folderUri));
        if (folder == null) {
            prefStatus.setSummary("");
            return;
        }
        final GarminAgpsStatus agpsStatus;
        final DocumentFile localFile = folder.findFile(filename);
        if (localFile != null && localFile.isFile() && localFile.canRead()) {
            if (localFile.lastModified() < prefs.getLong(GarminPreferences.agpsUpdateTime(url), 0L)) {
                agpsStatus = GarminAgpsStatus.CURRENT;
            } else {
                agpsStatus = GarminAgpsStatus.PENDING;
            }
        } else {
            agpsStatus = GarminAgpsStatus.MISSING;
        }
        prefStatus.setSummary(handler.getContext().getString(agpsStatus.getText()));
    }

    @Override
    public Set<String> getPreferenceKeysWithSummary() {
        return Collections.emptySet();
    }

    public static final Creator<GarminSettingsCustomizer> CREATOR = new Creator<GarminSettingsCustomizer>() {
        @Override
        public GarminSettingsCustomizer createFromParcel(final Parcel in) {
            return new GarminSettingsCustomizer();
        }

        @Override
        public GarminSettingsCustomizer[] newArray(final int size) {
            return new GarminSettingsCustomizer[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
    }
}
