package p.packer.services;

import com.fasterxml.jackson.databind.ObjectMapper;
import p.packer.PackerWorkspacePaths;
import p.packer.messages.InitWorkspaceRequest;
import p.packer.messages.InitWorkspaceResult;
import p.packer.messages.PackerOperationStatus;
import p.packer.messages.PackerProjectContext;
import p.packer.models.PackerRegistryEntry;
import p.packer.models.PackerRegistryState;
import p.packer.repositories.FileSystemPackerRegistryRepository;

import java.nio.file.Files;
import java.nio.file.Path;
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(final ObjectMapper mapper) {
        this(new FileSystemPackerRegistryRepository(mapper), new PackerIdentityAllocator(), new PackerRegistryLookup());
    }

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

    public InitWorkspaceResult initWorkspace(final InitWorkspaceRequest request) {
        final PackerProjectContext project = Objects.requireNonNull(request, "request").project();
        try {
            Files.createDirectories(PackerWorkspacePaths.assetsRoot(project));
            Files.createDirectories(PackerWorkspacePaths.registryDirectory(project));
            final var 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(final PackerProjectContext project) {
        return registryRepository.load(project);
    }

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

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

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

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

    public PackerRegistryLookup lookup() {
        return registryLookup;
    }
}
