/*
 * @Copyright 2018-2026 HardBackNutter
 * @License GNU General Public License
 *
 * This file is part of NeverTooManyBooks.
 *
 * NeverTooManyBooks 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.
 *
 * NeverTooManyBooks 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 NeverTooManyBooks. If not, see <http://www.gnu.org/licenses/>.
 */
package com.hardbacknutter.nevertoomanybooks.settings;

import android.content.Context;
import android.os.Bundle;

import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;

import java.io.IOException;
import java.util.Locale;

import com.hardbacknutter.nevertoomanybooks.BuildConfig;
import com.hardbacknutter.nevertoomanybooks.R;
import com.hardbacknutter.nevertoomanybooks.ServiceLocator;
import com.hardbacknutter.nevertoomanybooks.core.tasks.TaskProgress;
import com.hardbacknutter.nevertoomanybooks.covers.CoverVolume;
import com.hardbacknutter.nevertoomanybooks.tasks.StorageMoverTask;
import com.hardbacknutter.nevertoomanybooks.utils.AppLocale;
import com.hardbacknutter.nevertoomanybooks.utils.ReorderHelper;
import com.hardbacknutter.util.livedataevent.LiveDataEvent;

/**
 * Shared on the Activity level as it's needed by more than 1 Fragment.
 * <p>
 * Note that {@link #forceRebuildBooklist} and {@link #forceActivityRecreation}
 * are somewhat overlapping in functionality.
 */
@SuppressWarnings("WeakerAccess")
public class SettingsViewModel
        extends ViewModel {

    private final StorageMoverTask storageMoverTask = new StorageMoverTask();
    private boolean forceActivityRecreation;

    private boolean forceRebuildBooklist;

    /**
     * Used to be able to reset this pref to what it was when this fragment started.
     */
    private boolean storedTitleOrderBy;

    /**
     * Used to be able to reset this pref to what it was when this fragment started.
     */
    private int storedVolumeIndex;
    /**
     * Set using {@link SettingsInput} in the startup routines
     * to indicate the storage volume as configured was not found at startup.
     */
    private boolean missingStorageVolume;

    private String[] uiLanguageEntryValues;
    private String[] uiLanguageEntries;

    private boolean initDone;

    /**
     * Pseudo constructor.
     *
     * @param context Current context
     * @param args    {@link Fragment#getArguments()}
     */
    public void init(@NonNull final Context context,
                     @Nullable final Bundle args) {
        if (!initDone) {
            initDone = true;

            storedVolumeIndex = CoverVolume.getVolume();
            storedTitleOrderBy = ReorderHelper.isSortReordered();

            if (args != null) {
                final SettingsInput settingsInput = SettingsInput.fromBundle(args);
                missingStorageVolume = settingsInput.isStorageVolumeMissing();
            }
        }

        // ALWAYS refresh!
        initLanguages(context);
    }

    private void initLanguages(@NonNull final Context context) {
        final AppLocale appLocale = ServiceLocator.getInstance().getAppLocale();
        final Locale userLocale = context.getResources().getConfiguration().getLocales().get(0);
        final String[] tmpEntryValues = BuildConfig.SUPPORTED_LOCALES;

        uiLanguageEntries = new String[tmpEntryValues.length + 1];
        uiLanguageEntryValues = new String[tmpEntryValues.length + 1];

        uiLanguageEntryValues[0] = AppLocale.SYSTEM_LANGUAGE;
        uiLanguageEntries[0] = context.getString(R.string.pt_ui_system_locale);

        for (int i = 0; i < tmpEntryValues.length; i++) {
            uiLanguageEntryValues[i + 1] = tmpEntryValues[i];
            final Locale locale = appLocale
                    .getLocale(tmpEntryValues[i], userLocale)
                    // We should never get here... flw
                    .orElse(userLocale);
            // The NAME, i.e. including country, script,...
            uiLanguageEntries[i + 1] = locale.getDisplayName(locale);
        }
    }

    @NonNull
    public String[] getUiLanguageEntryValues() {
        return uiLanguageEntryValues;
    }

    @NonNull
    public String[] getUiLanguageEntries() {
        return uiLanguageEntries;
    }

    boolean isForceActivityRecreation() {
        return forceActivityRecreation;
    }

    public void setForceActivityRecreation() {
        forceActivityRecreation = true;
    }

    public boolean isForceRebuildBooklist() {
        return forceRebuildBooklist;
    }

    public void setForceRebuildBooklist() {
        this.forceRebuildBooklist = true;
    }

    public boolean getStoredTitleOrderBy() {
        return storedTitleOrderBy;
    }

    public boolean isMissingStorageVolume() {
        return missingStorageVolume;
    }

    public int getStoredVolumeIndex() {
        return storedVolumeIndex;
    }

    /**
     * Start the task moving the data.
     *
     * @param context     Current context
     * @param sourceIndex 0..
     * @param destIndex   0..
     *
     * @throws IOException on generic/other IO failures
     */
    void moveData(@NonNull final Context context,
                     final int sourceIndex,
                  final int destIndex)
            throws IOException {
        storageMoverTask.start(context, sourceIndex, destIndex);
    }

    @NonNull
    LiveData<LiveDataEvent<TaskProgress>> onProgress() {
        return storageMoverTask.onProgress();
    }

    /**
     * Observable to receive cancellation.
     *
     * @return the result is one of {@link StorageMoverTask#CANCELLED}
     *         or {@link StorageMoverTask#CANCELLED_NO_SPACE_ON_DISK}
     */
    @NonNull
    LiveData<LiveDataEvent<Integer>> onMoveCancelled() {
        return storageMoverTask.onCancelled();
    }

    /**
     * Observable to receive failure.
     *
     * @return the result is the Exception
     */
    @NonNull
    LiveData<LiveDataEvent<Throwable>> onMoveFailure() {
        return storageMoverTask.onFailure();
    }

    /**
     * Observable to receive success.
     *
     * @return the result is the destination volume index
     */
    @NonNull
    LiveData<LiveDataEvent<Integer>> onMoveFinished() {
        return storageMoverTask.onFinished();
    }

    void cancelTask(@IdRes final int taskId) {
        if (taskId == storageMoverTask.getTaskId()) {
            storageMoverTask.cancel();
        } else {
            throw new IllegalArgumentException("taskId=" + taskId);
        }
    }
}
