package p.packer.services;

import p.packer.models.PackerAssetDeclarationParseResult;
import p.packer.models.PackerRegistryEntry;
import p.packer.models.PackerRegistryState;
import p.packer.models.PackerRuntimeAsset;
import p.packer.models.PackerRuntimeSnapshot;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

public final class PackerRuntimePatchService {
    private final PackerAssetDeclarationParser declarationParser;

    public PackerRuntimePatchService(PackerAssetDeclarationParser declarationParser) {
        this.declarationParser = Objects.requireNonNull(declarationParser, "declarationParser");
    }

    public PackerRuntimeSnapshot afterCreateAsset(
            PackerRuntimeSnapshot snapshot,
            long generation,
            PackerRegistryState updatedRegistry,
            PackerRegistryEntry entry,
            Path assetRoot,
            Path manifestPath) {
        final PackerAssetDeclarationParseResult parsed = declarationParser.parse(manifestPath);
        final List<PackerRuntimeAsset> updatedAssets = new ArrayList<>(snapshot.assets().stream()
                .filter(candidate -> !candidate.assetRoot().equals(assetRoot.toAbsolutePath().normalize()))
                .toList());
        updatedAssets.add(new PackerRuntimeAsset(
                assetRoot,
                manifestPath,
                Optional.of(entry),
                parsed));
        updatedAssets.sort(Comparator.comparing(asset -> asset.assetRoot().toString(), String.CASE_INSENSITIVE_ORDER));
        return new PackerRuntimeSnapshot(generation, updatedRegistry, updatedAssets);
    }

    public PackerRuntimeSnapshot afterRegisterAsset(
            PackerRuntimeSnapshot snapshot,
            long generation,
            PackerRegistryState updatedRegistry,
            PackerRegistryEntry entry,
            Path assetRoot) {
        final List<PackerRuntimeAsset> updatedAssets = new ArrayList<>();
        boolean patched = false;
        for (PackerRuntimeAsset asset : snapshot.assets()) {
            if (asset.assetRoot().equals(assetRoot.toAbsolutePath().normalize())) {
                updatedAssets.add(new PackerRuntimeAsset(
                        asset.assetRoot(),
                        asset.manifestPath(),
                        Optional.of(entry),
                        asset.parsedDeclaration()));
                patched = true;
            } else {
                updatedAssets.add(asset);
            }
        }
        if (!patched) {
            throw new IllegalStateException("Unable to patch runtime snapshot for unregistered asset: " + assetRoot);
        }
        return new PackerRuntimeSnapshot(generation, updatedRegistry, updatedAssets);
    }
}
