package p.studio.workspaces.assets.details.bank;

import p.studio.workspaces.assets.messages.AssetWorkspaceAssetDetails;
import p.studio.workspaces.assets.messages.AssetWorkspaceBankCompositionFile;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;

abstract class AssetDetailsAbstractBankCompositionFamilySupport implements AssetDetailsBankCompositionFamilySupport {
    @Override
    public AssetDetailsBankCompositionDraft createDraft(AssetWorkspaceAssetDetails details) {
        final List<AssetWorkspaceBankCompositionFile> selectedFiles = details.bankComposition().selectedFiles();
        final var selectedPaths = selectedFiles.stream().map(AssetWorkspaceBankCompositionFile::path).collect(java.util.stream.Collectors.toSet());
        final List<AssetWorkspaceBankCompositionFile> availableFiles = details.bankComposition().availableFiles().stream()
                .filter(file -> !selectedPaths.contains(file.path()))
                .toList();
        return new AssetDetailsBankCompositionDraft(availableFiles, selectedFiles);
    }

    @Override
    public AssetDetailsBankCompositionDraft moveToSelected(
            AssetDetailsBankCompositionDraft draft,
            List<AssetWorkspaceBankCompositionFile> files) {
        final List<AssetWorkspaceBankCompositionFile> movableFiles = selectMovableFiles(draft, files);
        return draft.removeFromAvailable(movableFiles).appendToSelected(movableFiles);
    }

    @Override
    public AssetDetailsBankCompositionDraft moveToAvailable(
            AssetDetailsBankCompositionDraft draft,
            List<AssetWorkspaceBankCompositionFile> files) {
        final var returnedFiles = new ArrayList<>(files);
        returnedFiles.sort(java.util.Comparator.comparing(AssetWorkspaceBankCompositionFile::path, String.CASE_INSENSITIVE_ORDER));
        return draft.removeFromSelected(files).appendToAvailable(returnedFiles);
    }

    @Override
    public AssetDetailsBankCompositionDraft moveUp(AssetDetailsBankCompositionDraft draft, int selectedIndex) {
        if (selectedIndex <= 0 || selectedIndex >= draft.selectedFiles().size()) {
            return draft;
        }
        final List<AssetWorkspaceBankCompositionFile> reordered = new ArrayList<>(draft.selectedFiles());
        final AssetWorkspaceBankCompositionFile moved = reordered.remove(selectedIndex);
        reordered.add(selectedIndex - 1, moved);
        return new AssetDetailsBankCompositionDraft(draft.availableFiles(), reordered);
    }

    @Override
    public AssetDetailsBankCompositionDraft moveDown(AssetDetailsBankCompositionDraft draft, int selectedIndex) {
        if (selectedIndex < 0 || selectedIndex >= draft.selectedFiles().size() - 1) {
            return draft;
        }
        final List<AssetWorkspaceBankCompositionFile> reordered = new ArrayList<>(draft.selectedFiles());
        final AssetWorkspaceBankCompositionFile moved = reordered.remove(selectedIndex);
        reordered.add(selectedIndex + 1, moved);
        return new AssetDetailsBankCompositionDraft(draft.availableFiles(), reordered);
    }

    protected abstract boolean canAdd(
            AssetDetailsBankCompositionDraft currentDraft,
            List<AssetWorkspaceBankCompositionFile> accepted,
            AssetWorkspaceBankCompositionFile candidate);

    private List<AssetWorkspaceBankCompositionFile> selectMovableFiles(
            AssetDetailsBankCompositionDraft draft,
            List<AssetWorkspaceBankCompositionFile> files) {
        final var requested = new LinkedHashSet<>(files);
        final List<AssetWorkspaceBankCompositionFile> movable = new ArrayList<>();
        for (AssetWorkspaceBankCompositionFile file : draft.availableFiles()) {
            if (!requested.contains(file)) {
                continue;
            }
            if (canAdd(draft, movable, file)) {
                movable.add(file);
            }
        }
        return List.copyOf(movable);
    }
}
