package p.packer.services;

import p.packer.PackerWorkspacePaths;
import p.packer.messages.PackerProjectContext;
import p.packer.models.PackerRegistryEntry;
import p.packer.models.PackerRegistryState;

import java.nio.file.Path;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

public final class PackerIdentityAllocator {
    public PackerRegistryEntry allocate(
            PackerProjectContext project,
            PackerRegistryState state,
            Path assetRoot) {
        Objects.requireNonNull(project, "project");
        Objects.requireNonNull(state, "state");
        final Path normalizedAssetRoot = Objects.requireNonNull(assetRoot, "assetRoot").toAbsolutePath().normalize();
        final String relativeRoot = PackerWorkspacePaths.relativeAssetRoot(project, normalizedAssetRoot);
        final boolean alreadyRegistered = state.assets().stream().anyMatch(entry -> entry.root().equals(relativeRoot));
        if (alreadyRegistered) {
            throw new p.packer.exceptions.PackerRegistryException("Asset root is already registered: " + relativeRoot);
        }
        return new PackerRegistryEntry(state.nextAssetId(), UUID.randomUUID().toString(), relativeRoot);
    }

    public PackerRegistryEntry registerExisting(
            PackerProjectContext project,
            PackerRegistryState state,
            Path assetRoot,
            String assetUuid) {
        Objects.requireNonNull(project, "project");
        Objects.requireNonNull(state, "state");
        final Path normalizedAssetRoot = Objects.requireNonNull(assetRoot, "assetRoot").toAbsolutePath().normalize();
        final String relativeRoot = PackerWorkspacePaths.relativeAssetRoot(project, normalizedAssetRoot);
        final String normalizedAssetUuid = Objects.requireNonNull(assetUuid, "assetUuid").trim();
        if (normalizedAssetUuid.isBlank()) {
            throw new IllegalArgumentException("assetUuid must not be blank");
        }
        final boolean alreadyRegisteredRoot = state.assets().stream().anyMatch(entry -> entry.root().equals(relativeRoot));
        if (alreadyRegisteredRoot) {
            throw new p.packer.exceptions.PackerRegistryException("Asset root is already registered: " + relativeRoot);
        }
        final boolean alreadyRegisteredUuid = state.assets().stream().anyMatch(entry -> entry.assetUuid().equals(normalizedAssetUuid));
        if (alreadyRegisteredUuid) {
            throw new p.packer.exceptions.PackerRegistryException("Asset UUID is already registered: " + normalizedAssetUuid);
        }
        return new PackerRegistryEntry(state.nextAssetId(), normalizedAssetUuid, relativeRoot);
    }

    public PackerRegistryState append(PackerRegistryState state, PackerRegistryEntry entry) {
        Objects.requireNonNull(state, "state");
        Objects.requireNonNull(entry, "entry");
        final List<PackerRegistryEntry> updated = state.assets().stream()
                .collect(java.util.stream.Collectors.toCollection(java.util.ArrayList::new));
        updated.add(entry);
        updated.sort(Comparator.comparingInt(PackerRegistryEntry::assetId));
        return new PackerRegistryState(state.schemaVersion(), entry.assetId() + 1, updated);
    }
}
