package p.packer;

import p.packer.events.PackerEventSink;
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(
            PackerWorkspaceService workspaceService,
            PackerRuntimeRegistry runtimeRegistry,
            PackerProjectWriteCoordinator writeCoordinator) {
        this.workspaceService = Objects.requireNonNull(workspaceService, "workspaceService");
        this.runtimeRegistry = Objects.requireNonNull(runtimeRegistry, "runtimeRegistry");
        this.writeCoordinator = Objects.requireNonNull(writeCoordinator, "writeCoordinator");
    }

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

    public PackerWorkspaceService workspaceService() {
        return workspaceService;
    }

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