package org.jabref.gui.groups;

import java.util.EnumSet;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SetProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleSetProperty;
import javafx.collections.FXCollections;

import org.jabref.model.groups.GroupHierarchyType;

import com.google.common.annotations.VisibleForTesting;

public class GroupsPreferences {

    private final SetProperty<GroupViewMode> groupViewMode;
    private final BooleanProperty shouldAutoAssignGroup;
    private final BooleanProperty shouldDisplayGroupCount;
    private final BooleanProperty shouldAutoIncludeSelectedEntries;
    private final ObjectProperty<GroupHierarchyType> defaultHierarchicalContext;
    private final BooleanProperty showAiChatButton;

    public GroupsPreferences(boolean viewModeIntersection,
                             boolean viewModeFilter,
                             boolean viewModeInvert,
                             boolean shouldAutoAssignGroup,
                             boolean shouldDisplayGroupCount,
                             boolean shouldAutoIncludeSelectedEntries,
                             GroupHierarchyType defaultHierarchicalContext,
                             boolean showAiChatButton) {

        this.groupViewMode = new SimpleSetProperty<>(FXCollections.observableSet());
        this.shouldAutoAssignGroup = new SimpleBooleanProperty(shouldAutoAssignGroup);
        this.shouldDisplayGroupCount = new SimpleBooleanProperty(shouldDisplayGroupCount);
        this.shouldAutoIncludeSelectedEntries = new SimpleBooleanProperty(shouldAutoIncludeSelectedEntries);
        this.defaultHierarchicalContext = new SimpleObjectProperty<>(defaultHierarchicalContext);
        this.showAiChatButton = new SimpleBooleanProperty(showAiChatButton);

        if (viewModeIntersection) {
            this.groupViewMode.add(GroupViewMode.INTERSECTION);
        }
        if (viewModeFilter) {
            this.groupViewMode.add(GroupViewMode.FILTER);
        }
        if (viewModeInvert) {
            this.groupViewMode.add(GroupViewMode.INVERT);
        }
    }

    private GroupsPreferences() {
        this(
                true,                             // Default view mode intersection
                true,                             // Default view mode filter
                false,                            // Default view mode invert
                true,                             // Default auto assign group
                true,                             // Default display group content
                true,                             // Default include selected entries in new explicit groups
                GroupHierarchyType.INDEPENDENT,   // Default hierarchical context
                true                              // Default view mode for the AI chat button
        );
    }

    @VisibleForTesting
    public GroupsPreferences(EnumSet<GroupViewMode> groupViewMode,
                             boolean shouldAutoAssignGroup,
                             boolean shouldDisplayGroupCount,
                             boolean shouldAutoIncludeSelectedEntries,
                             GroupHierarchyType defaultHierarchicalContext,
                             boolean showAiChatButton) {
        this.groupViewMode = new SimpleSetProperty<>(FXCollections.observableSet(groupViewMode));
        this.shouldAutoAssignGroup = new SimpleBooleanProperty(shouldAutoAssignGroup);
        this.shouldDisplayGroupCount = new SimpleBooleanProperty(shouldDisplayGroupCount);
        this.shouldAutoIncludeSelectedEntries = new SimpleBooleanProperty(shouldAutoIncludeSelectedEntries);
        this.defaultHierarchicalContext = new SimpleObjectProperty<>(defaultHierarchicalContext);
        this.showAiChatButton = new SimpleBooleanProperty(showAiChatButton);
    }

    public static GroupsPreferences getDefault() {
        return new GroupsPreferences();
    }

    public EnumSet<GroupViewMode> getGroupViewMode() {
        if (groupViewMode.isEmpty()) {
            return EnumSet.noneOf(GroupViewMode.class);
        }
        return EnumSet.copyOf(groupViewMode);
    }

    public SetProperty<GroupViewMode> groupViewModeProperty() {
        return groupViewMode;
    }

    public void setGroupViewMode(GroupViewMode mode, boolean value) {
        if (value) {
            groupViewMode.add(mode);
        } else {
            groupViewMode.remove(mode);
        }
    }

    public boolean shouldAutoAssignGroup() {
        return shouldAutoAssignGroup.getValue();
    }

    public BooleanProperty autoAssignGroupProperty() {
        return shouldAutoAssignGroup;
    }

    public void setAutoAssignGroup(boolean shouldAutoAssignGroup) {
        this.shouldAutoAssignGroup.set(shouldAutoAssignGroup);
    }

    public boolean shouldDisplayGroupCount() {
        return shouldDisplayGroupCount.getValue();
    }

    public BooleanProperty displayGroupCountProperty() {
        return shouldDisplayGroupCount;
    }

    public void setDisplayGroupCount(boolean shouldDisplayGroupCount) {
        this.shouldDisplayGroupCount.set(shouldDisplayGroupCount);
    }

    public boolean shouldAutoIncludeSelectedEntries() {
        return shouldAutoIncludeSelectedEntries.getValue();
    }

    public BooleanProperty autoIncludeSelectedEntriesProperty() {
        return shouldAutoIncludeSelectedEntries;
    }

    public void setAutoIncludeSelectedEntries(boolean shouldAutoIncludeSelectedEntries) {
        this.shouldAutoIncludeSelectedEntries.set(shouldAutoIncludeSelectedEntries);
    }

    public GroupHierarchyType getDefaultHierarchicalContext() {
        return defaultHierarchicalContext.get();
    }

    public ObjectProperty<GroupHierarchyType> defaultHierarchicalContextProperty() {
        return defaultHierarchicalContext;
    }

    public void setDefaultHierarchicalContext(GroupHierarchyType defaultHierarchicalContext) {
        this.defaultHierarchicalContext.set(defaultHierarchicalContext);
    }

    public boolean showAiChatButton() {
        return showAiChatButton.getValue();
    }

    public BooleanProperty showAiChatButtonProperty() {
        return showAiChatButton;
    }

    public void setShowAiChatButton(boolean showAiChatButton) {
        this.showAiChatButton.set(showAiChatButton);
    }
}
