package p.packer.services;

import p.packer.messages.PackerOperationStatus;
import p.packer.messages.PackerProjectContext;
import p.packer.messages.InitWorkspaceRequest;
import p.packer.messages.InitWorkspaceResult;
import p.packer.models.PackerRegistryEntry;
import p.packer.models.PackerRegistryState;

import java.nio.file.Files;
import java.util.List;
import java.util.Objects;

public final class PackerWorkspaceFoundation {
    private final FileSystemPackerRegistryRepository registryRepository;
    private final PackerIdentityAllocator identityAllocator;
    private final PackerRegistryLookup registryLookup;

    public PackerWorkspaceFoundation() {
        this(new FileSystemPackerRegistryRepository(), new PackerIdentityAllocator(), new PackerRegistryLookup());
    }

    public PackerWorkspaceFoundation(
            FileSystemPackerRegistryRepository registryRepository,
            PackerIdentityAllocator identityAllocator,
            PackerRegistryLookup registryLookup) {
        this.registryRepository = Objects.requireNonNull(registryRepository, "registryRepository");
        this.identityAllocator = Objects.requireNonNull(identityAllocator, "identityAllocator");
        this.registryLookup = Objects.requireNonNull(registryLookup, "registryLookup");
    }

    public InitWorkspaceResult initWorkspace(InitWorkspaceRequest request) {
        final PackerProjectContext project = Objects.requireNonNull(request, "request").project();
        try {
            Files.createDirectories(PackerWorkspacePaths.assetsRoot(project));
            Files.createDirectories(PackerWorkspacePaths.registryDirectory(project));
            final PackerRegistryState registryState = registryRepository.load(project);
            registryRepository.save(project, registryState);
            return new InitWorkspaceResult(
                    PackerOperationStatus.SUCCESS,
                    "Workspace initialized for packer control.",
                    PackerWorkspacePaths.registryPath(project),
                    List.of());
        } catch (Exception exception) {
            throw new p.packer.exceptions.PackerRegistryException("Unable to initialize workspace for " + project.projectId(), exception);
        }
    }

    public PackerRegistryState loadRegistry(PackerProjectContext project) {
        return registryRepository.load(project);
    }

    public void saveRegistry(PackerProjectContext project, PackerRegistryState state) {
        registryRepository.save(project, state);
    }

    public PackerRegistryEntry allocateIdentity(PackerProjectContext project, PackerRegistryState state, java.nio.file.Path assetRoot) {
        return identityAllocator.allocate(project, state, assetRoot);
    }

    public PackerRegistryEntry registerExistingAsset(
            PackerProjectContext project,
            PackerRegistryState state,
            java.nio.file.Path assetRoot,
            String assetUuid) {
        return identityAllocator.registerExisting(project, state, assetRoot, assetUuid);
    }

    public PackerRegistryState appendAllocatedEntry(PackerRegistryState state, PackerRegistryEntry entry) {
        return identityAllocator.append(state, entry);
    }

    public PackerRegistryLookup lookup() {
        return registryLookup;
    }
}
