package dev.dinauer.maven.maven.core;

import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import dev.dinauer.maven.maven.core.release.ReleaseVersion;
import dev.dinauer.maven.maven.core.snapshot.SnapshotVersion;
import dev.dinauer.maven.shared.UserReferencing;
import jakarta.persistence.*;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;

import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Entity
@Table(name = "artifact_id")
public class ArtifactId implements UserReferencing
{
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;

    @Column(name = "group_id_long")
    private String groupId;

    @Column(name = "artifact_id")
    private String artifactId;

    @ManyToOne(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "group_id")
    @JsonBackReference
    private GroupId group;

    @OneToMany(mappedBy = "artifact", cascade = CascadeType.REMOVE)
    @JsonManagedReference
    private List<ReleaseVersion> releaseVersions = new ArrayList<>();

    @OneToMany(mappedBy = "artifact", cascade = CascadeType.REMOVE)
    @JsonManagedReference
    private List<SnapshotVersion> snapshotVersions = new ArrayList<>();

    @Column(name = "updated_at")
    private ZonedDateTime updatedAt;

    @Column(name = "created_at")
    private ZonedDateTime createdAt;

    public String getId()
    {
        return id;
    }

    public ArtifactId setId(String id)
    {
        this.id = id;
        return this;
    }

    public String getGroupId()
    {
        return groupId;
    }

    public ArtifactId setGroupId(String groupId)
    {
        this.groupId = groupId;
        return this;
    }

    public String getArtifactId()
    {
        return artifactId;
    }

    public ArtifactId setArtifactId(String artifactId)
    {
        this.artifactId = artifactId;
        return this;
    }

    public GroupId getGroup()
    {
        return group;
    }

    public ArtifactId setGroup(GroupId groupId)
    {
        this.group = groupId;
        return this;
    }

    public List<Version> getVersions()
    {
        return Stream.concat(snapshotVersions.stream(), releaseVersions.stream()).sorted(Comparator.comparing(item -> new DefaultArtifactVersion(item.getVersion()))).toList().reversed();
    }

    public ArtifactId setVersions(List<ReleaseVersion> releaseVersions)
    {
        this.releaseVersions = releaseVersions;
        return this;
    }

    public ZonedDateTime getUpdatedAt()
    {
        return updatedAt;
    }

    public ArtifactId setUpdatedAt(ZonedDateTime updatedAt)
    {
        this.updatedAt = updatedAt;
        if (this.group != null)
        {
            this.group.setUpdatedAt(updatedAt);
        }
        return this;
    }

    public ZonedDateTime getCreatedAt()
    {
        return createdAt;
    }

    public ArtifactId setCreatedAt(ZonedDateTime createdAt)
    {
        this.createdAt = createdAt;
        return this;
    }

    public int getTotalPullCount()
    {
        int i = 0;
        for (ReleaseVersion releaseVersion : releaseVersions)
        {
            i = i + releaseVersion.getPullCount();
        }
        return i;
    }

    public List<SnapshotVersion> getSnapshotVersions()
    {
        return snapshotVersions;
    }

    public ArtifactId setSnapshotVersions(List<SnapshotVersion> snapshotVersions)
    {
        this.snapshotVersions = snapshotVersions;
        return this;
    }

    public List<ReleaseVersion> getReleaseVersions()
    {
        return releaseVersions.stream().sorted(Comparator.comparing(item -> new DefaultArtifactVersion(item.getVersion()))).toList().reversed();
    }

    public ArtifactId setReleaseVersions(List<ReleaseVersion> releaseVersions)
    {
        this.releaseVersions = releaseVersions;
        return this;
    }

    @Override
    public Set<String> getUserIds()
    {
        return getVersions().stream().flatMap(version -> version.getUserIds().stream()).collect(Collectors.toSet());
    }
}
