package com.r35157.nenjim.service.journal.model;

import com.r35157.libs.valuetypes.basic.SemanticVersion;
import com.r35157.nenjim.service.journal.valuetypes.ContentDigest;
import com.r35157.nenjim.service.journal.valuetypes.DependencyTarget;

import java.time.Instant;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

/** All knowledge about one exact artifact release in one Journal snapshot. */
public record ArtifactRelease(
        SemanticVersion version,
        String license,
        Instant publishedAt,
        List<ContentDigest> contentDigests,
        long contentSize,
        List<ArtifactDependency> dependencies) {
    public ArtifactRelease {
        Objects.requireNonNull(version, "version");
        Objects.requireNonNull(license, "license");
        if (license.isBlank()) {
            throw new IllegalArgumentException("Release license cannot be blank");
        }
        Objects.requireNonNull(publishedAt, "publishedAt");
        if (publishedAt.getNano() % 1_000_000 != 0) {
            throw new IllegalArgumentException("Release publication time must have millisecond precision");
        }
        if (contentSize < 0) {
            throw new IllegalArgumentException("Release content size cannot be negative");
        }

        contentDigests = copyDigests(contentDigests);
        dependencies = copyDependencies(dependencies);
    }

    public Optional<ContentDigest> contentDigest(String scheme) {
        Objects.requireNonNull(scheme, "scheme");
        return contentDigests.stream().filter(digest -> digest.scheme().equals(scheme)).findFirst();
    }

    public Optional<ArtifactDependency> dependency(DependencyTarget target) {
        Objects.requireNonNull(target, "target");
        return dependencies.stream().filter(dependency -> dependency.target().equals(target)).findFirst();
    }

    private static List<ContentDigest> copyDigests(List<ContentDigest> digests) {
        Objects.requireNonNull(digests, "contentDigests");
        if (digests.isEmpty()) {
            throw new IllegalArgumentException("A release requires at least one content digest");
        }
        Set<String> schemes = new HashSet<>();
        for (ContentDigest digest : digests) {
            Objects.requireNonNull(digest, "content digest");
            if (!schemes.add(digest.scheme())) {
                throw new IllegalArgumentException("Duplicate content digest scheme: '" + digest.scheme() + "'");
            }
        }
        return List.copyOf(digests);
    }

    private static List<ArtifactDependency> copyDependencies(List<ArtifactDependency> dependencies) {
        Objects.requireNonNull(dependencies, "dependencies");
        Set<DependencyTarget> targets = new HashSet<>();
        for (ArtifactDependency dependency : dependencies) {
            Objects.requireNonNull(dependency, "dependency");
            if (!targets.add(dependency.target())) {
                throw new IllegalArgumentException("Duplicate dependency target: '" + dependency.target() + "'");
            }
        }
        return List.copyOf(dependencies);
    }
}
