package org.jabref.gui.preferences.protectedterms;

import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.scene.control.ButtonType;
import javafx.scene.control.DialogPane;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;

import org.jabref.gui.DialogService;
import org.jabref.gui.desktop.os.NativeDesktop;
import org.jabref.gui.externalfiletype.ExternalFileType;
import org.jabref.gui.externalfiletype.ExternalFileTypes;
import org.jabref.gui.frame.ExternalApplicationsPreferences;
import org.jabref.gui.preferences.PreferenceTabViewModel;
import org.jabref.gui.util.FileDialogConfiguration;
import org.jabref.logic.FilePreferences;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.protectedterms.ProtectedTermsList;
import org.jabref.logic.protectedterms.ProtectedTermsLoader;
import org.jabref.logic.protectedterms.ProtectedTermsPreferences;
import org.jabref.logic.util.StandardFileType;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.util.OptionalUtil;

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

public class ProtectedTermsTabViewModel implements PreferenceTabViewModel {
    private static final Logger LOGGER = LoggerFactory.getLogger(ProtectedTermsTabViewModel.class);

    private final ProtectedTermsLoader termsLoader;
    private final ListProperty<ProtectedTermsListItemModel> termsFilesProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
    private final DialogService dialogService;
    private final ExternalApplicationsPreferences externalApplicationsPreferences;
    private final FilePreferences filePreferences;
    private final ProtectedTermsPreferences protectedTermsPreferences;

    public ProtectedTermsTabViewModel(ProtectedTermsLoader termsLoader,
                                      DialogService dialogService,
                                      ExternalApplicationsPreferences externalApplicationsPreferences,
                                      FilePreferences filePreferences,
                                      ProtectedTermsPreferences protectedTermsPreferences) {
        this.termsLoader = termsLoader;
        this.dialogService = dialogService;
        this.externalApplicationsPreferences = externalApplicationsPreferences;
        this.filePreferences = filePreferences;
        this.protectedTermsPreferences = protectedTermsPreferences;
    }

    @Override
    public void setValues() {
        termsFilesProperty.clear();
        termsFilesProperty.addAll(termsLoader.getProtectedTermsLists().stream().map(ProtectedTermsListItemModel::new).toList());
    }

    @Override
    public void storeSettings() {
        List<String> enabledExternalList = new ArrayList<>();
        List<String> disabledExternalList = new ArrayList<>();
        List<String> enabledInternalList = new ArrayList<>();
        List<String> disabledInternalList = new ArrayList<>();

        for (ProtectedTermsList list : termsFilesProperty.getValue().stream()
                                                         .map(ProtectedTermsListItemModel::getTermsList).toList()) {
            if (list.isInternalList()) {
                if (list.isEnabled()) {
                    enabledInternalList.add(list.getLocation());
                } else {
                    disabledInternalList.add(list.getLocation());
                }
            } else {
                if (list.isEnabled()) {
                    enabledExternalList.add(list.getLocation());
                } else {
                    disabledExternalList.add(list.getLocation());
                }
            }
        }

        protectedTermsPreferences.setEnabledInternalTermLists(enabledInternalList);
        protectedTermsPreferences.setEnabledExternalTermLists(enabledExternalList);
        protectedTermsPreferences.setDisabledInternalTermLists(disabledInternalList);
        protectedTermsPreferences.setDisabledExternalTermLists(disabledExternalList);

        termsLoader.update(protectedTermsPreferences);
    }

    public void addFile() {
        FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder()
                .addExtensionFilter(Localization.lang("Protected terms file"), StandardFileType.TERMS)
                .withDefaultExtension(Localization.lang("Protected terms file"), StandardFileType.TERMS)
                .withInitialDirectory(filePreferences.getWorkingDirectory())
                .build();

        dialogService.showFileOpenDialog(fileDialogConfiguration)
                     .ifPresent(file -> {
                         Path fileName = file.toAbsolutePath();
                         termsFilesProperty.add(new ProtectedTermsListItemModel(ProtectedTermsLoader.readProtectedTermsListFromFile(fileName, true)));
                     });
    }

    public void removeList(ProtectedTermsListItemModel itemModel) {
        ProtectedTermsList list = itemModel.getTermsList();
        if (!list.isInternalList() && dialogService.showConfirmationDialogAndWait(Localization.lang("Remove protected terms file"),
                Localization.lang("Are you sure you want to remove the protected terms file?"),
                Localization.lang("Remove protected terms file"),
                Localization.lang("Cancel"))) {
            itemModel.enabledProperty().setValue(false);
            if (!termsFilesProperty.remove(itemModel)) {
                LOGGER.info("Problem removing protected terms file");
            }
        }
    }

    public void createNewFile() {
        dialogService.showCustomDialogAndWait(new NewProtectedTermsFileDialog(termsFilesProperty, dialogService, filePreferences));
    }

    public void edit(ProtectedTermsListItemModel file) {
        Optional<ExternalFileType> termsFileType = OptionalUtil.<ExternalFileType>orElse(
                ExternalFileTypes.getExternalFileTypeByExt("terms", externalApplicationsPreferences),
                ExternalFileTypes.getExternalFileTypeByExt("txt", externalApplicationsPreferences)
        );

        String fileName = file.getTermsList().getLocation();
        try {
            NativeDesktop.openExternalFileAnyFormat(new BibDatabaseContext(), externalApplicationsPreferences, filePreferences, fileName, termsFileType);
        } catch (IOException e) {
            LOGGER.warn("Problem open protected terms file editor", e);
        }
    }

    public void displayContent(ProtectedTermsListItemModel itemModel) {
        ProtectedTermsList list = itemModel.getTermsList();
        TextArea listingView = new TextArea(list.getTermListing());
        listingView.setEditable(false);

        ScrollPane scrollPane = new ScrollPane();
        scrollPane.setFitToHeight(true);
        scrollPane.setFitToWidth(true);
        scrollPane.setContent(listingView);

        DialogPane dialogPane = new DialogPane();
        dialogPane.setContent(scrollPane);

        dialogService.showCustomDialogAndWait(list.getDescription() + " - " + list.getLocation(), dialogPane, ButtonType.OK);
    }

    public void reloadList(ProtectedTermsListItemModel oldItemModel) {
        ProtectedTermsList oldList = oldItemModel.getTermsList();
        ProtectedTermsList newList = ProtectedTermsLoader.readProtectedTermsListFromFile(Path.of(oldList.getLocation()), oldList.isEnabled());
        int index = termsFilesProperty.indexOf(oldItemModel);
        if (index >= 0) {
            termsFilesProperty.set(index, new ProtectedTermsListItemModel(newList));
        } else {
            LOGGER.warn("Problem reloading protected terms file {}.", oldList.getLocation());
        }
    }

    public ListProperty<ProtectedTermsListItemModel> termsFilesProperty() {
        return termsFilesProperty;
    }
}
