package dev.dinauer.maven.maven.core;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import dev.dinauer.maven.jpa.maven.ArtifactId;
import dev.dinauer.maven.jpa.maven.Jar;
import dev.dinauer.maven.jpa.maven.Pom;
import dev.dinauer.maven.jpa.maven.Version;
import dev.dinauer.maven.maven.core.model.ExtensionParser;
import dev.dinauer.maven.maven.core.model.File;
import dev.dinauer.maven.maven.token.TokenService;
import dev.dinauer.maven.metadata.Metadata;
import dev.dinauer.maven.maven.core.model.FileHash;
import dev.dinauer.maven.maven.core.model.MavenContext;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jdk.jshell.spi.ExecutionControl;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.NotImplementedException;

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Optional;

@ApplicationScoped
public class Service
{
    @Inject
    ArtifactService artifactService;

    @Inject
    JarService jarService;

    @Inject
    PomService pomService;

    @Transactional
    public Response upload(String path, byte[] body)
    {
        MavenContext mavenContext = MavenContextProvider.parse(path);
        switch (mavenContext.file().getType())
        {
            case JAR ->
            {
                if (mavenContext.version().getSnapshot())
                {
                    throw new WebApplicationException(501);
                }
                if (FileHash.NONE.equals(mavenContext.file().getHash()))
                {
                    return jarService.store(mavenContext, body);
                }
                return Response.accepted().build();
            }
            case POM ->
            {
                if (FileHash.NONE.equals(mavenContext.file().getHash()))
                {
                    return pomService.store(mavenContext, body);
                }
                return Response.accepted().build();
            }
            case XML ->
            {
                return Response.accepted().build();
            }
        }
        throw new RuntimeException();
    }

    @Transactional
    public Response serve(String path) throws JsonProcessingException
    {
        MavenContext mavenContext = MavenContextProvider.parse(path);
        switch (mavenContext.file().getType())
        {
            case JAR ->
            {
                if (FileHash.NONE.equals(mavenContext.file().getHash()))
                {
                    return jarService.find(mavenContext);
                }
                return jarService.findHash(mavenContext);
            }
            case POM ->
            {
                if (FileHash.NONE.equals(mavenContext.file().getHash()))
                {
                    return pomService.find(mavenContext);
                }
                return pomService.findHash(mavenContext);
            }
            case XML ->
            {
                Optional<ArtifactId> artifactOptional = artifactService.find(mavenContext.groupId(), mavenContext.artifactId());
                if (artifactOptional.isPresent())
                {
                    ArtifactId artifact = artifactOptional.get();
                    String metadata = new XmlMapper().writeValueAsString(new Metadata(artifact.getGroupId(), artifact.getArtifactId(), null, artifact.getUpdatedAt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))));
                    if (mavenContext.file().getHash() == null)
                    {
                        return Response.ok().type(MediaType.APPLICATION_XML).entity(metadata).build();
                    }
                    switch (mavenContext.file().getHash())
                    {
                        case SHA1 ->
                        {
                            return Response.ok().type(MediaType.TEXT_PLAIN).entity(DigestUtils.sha1Hex(metadata)).build();
                        }
                        case MD5 ->
                        {
                            return Response.ok().type(MediaType.TEXT_PLAIN).entity(DigestUtils.md5Hex(metadata)).build();
                        }
                    }
                }
                return Response.status(Response.Status.NOT_FOUND).build();
            }
        }
        throw new RuntimeException();
    }
}
