package p.packer;

import com.fasterxml.jackson.databind.ObjectMapper;
import p.packer.events.PackerEventSink;
import p.packer.repositories.FileSystemPackerCacheRepository;
import p.packer.repositories.PackerAssetWalker;
import p.packer.repositories.PackerRuntimeAssetMaterializer;
import p.packer.repositories.PackerRuntimeLoader;
import p.packer.repositories.PackerRuntimeRegistry;
import p.packer.services.*;

import java.io.Closeable;
import java.util.Objects;

public final class Packer implements Closeable {
    private final PackerWorkspaceService workspaceService;
    private final PackerRuntimeRegistry runtimeRegistry;
    private final PackerProjectWriteCoordinator writeCoordinator;

    private Packer(
            final PackerWorkspaceService workspaceService,
            final PackerRuntimeRegistry runtimeRegistry,
            final PackerProjectWriteCoordinator writeCoordinator) {
        this.workspaceService = Objects.requireNonNull(workspaceService, "workspaceService");
        this.runtimeRegistry = Objects.requireNonNull(runtimeRegistry, "runtimeRegistry");
        this.writeCoordinator = Objects.requireNonNull(writeCoordinator, "writeCoordinator");
    }

    public static Packer bootstrap(final ObjectMapper mapper, final PackerEventSink eventSink) {
        final var resolvedEventSink = Objects.requireNonNull(eventSink, "eventSink");
        final var workspaceFoundation = new PackerWorkspaceFoundation(mapper);
        final var declarationParser = new PackerAssetDeclarationParser(mapper);
        final var assetWalker = new PackerAssetWalker(mapper);
        final var cacheRepository = new FileSystemPackerCacheRepository(mapper);
        final var assetMaterializer = new PackerRuntimeAssetMaterializer(assetWalker);
        final var runtimeLoader = new PackerRuntimeLoader(
                workspaceFoundation,
                declarationParser,
                cacheRepository,
                assetMaterializer);
        final var runtimeRegistry = new PackerRuntimeRegistry(runtimeLoader);
        final var assetReferenceResolver = new PackerAssetReferenceResolver(workspaceFoundation.lookup());
        final var assetDetailsService = new PackerAssetDetailsService(runtimeRegistry, assetReferenceResolver);
        final var assetActionReadService = new PackerAssetActionReadService(
                runtimeRegistry,
                assetReferenceResolver,
                workspaceFoundation.lookup());
        final var runtimePatchService = new PackerRuntimePatchService(declarationParser, assetMaterializer);
        final var writeCoordinator = new PackerProjectWriteCoordinator();
        return new Packer(new FileSystemPackerWorkspaceService(
                mapper,
                workspaceFoundation,
                assetDetailsService,
                assetActionReadService,
                runtimePatchService,
                runtimeRegistry,
                cacheRepository,
                writeCoordinator,
                resolvedEventSink), runtimeRegistry, writeCoordinator);
    }

    public PackerWorkspaceService workspaceService() {
        return workspaceService;
    }

    @Override
    public void close() {
        writeCoordinator.close();
        runtimeRegistry.disposeAll();
    }
}
