package org.carlspring.strongbox.artifact.coordinates;

import org.carlspring.strongbox.artifact.coordinates.versioning.SemanticVersion;
import org.carlspring.strongbox.providers.io.RepositoryPath;
import org.carlspring.strongbox.storage.metadata.nuget.NugetFormatException;
import org.carlspring.strongbox.storage.metadata.nuget.Nupkg;
import org.carlspring.strongbox.storage.metadata.nuget.Nuspec;
import org.carlspring.strongbox.storage.metadata.nuget.Nuspec.Metadata;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.util.*;

import javax.xml.bind.DatatypeConverter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

public class PathNupkg implements Nupkg
{

    private static final Logger logger = LoggerFactory.getLogger(PathNupkg.class);

    private RepositoryPath path;
    private Nuspec nuspecFile;
    private String hash;
    private NugetArtifactCoordinates artifactCoordinates;
    
    public PathNupkg(RepositoryPath path)
        throws NugetFormatException,
        UnsupportedEncodingException,
        IOException
    {
        Assert.notNull(path, "path should not be null");
        Assert.notNull(path.getArtifactEntry(), "artifact entry should not be null");
        
        this.path = path;
        this.artifactCoordinates = (NugetArtifactCoordinates) path.getArtifactEntry().getArtifactCoordinates();
        this.nuspecFile = createNuspecFile();
        this.hash = createHash();
    }

    public RepositoryPath getPath()
    {
        return path;
    }

    @Override
    public String getFileName()
    {
        return path.getFileName().toString();
    }

    @Override
    public String getHash()
    {
        return hash;
    }

    private String createHash()
        throws IOException,
        UnsupportedEncodingException
    {
        Map<String, RepositoryPath> checksumPathMap = path.getFileSystem().provider().resolveChecksumPathMap(path);
        if (checksumPathMap.isEmpty())
        {
            return null;
        }
        // Nuget package should have only one checksum digest algorithm.
        RepositoryPath checkSumPath = checksumPathMap.values().iterator().next();
        if (!Files.exists(checkSumPath))
        {
            logger.trace(String.format("Failed to resolve checksum file for [%s]", path));
            return DatatypeConverter.printBase64Binary(new byte[] {});
        }
        List<String> checkSumContents = Files.readAllLines(checkSumPath);
        if (checkSumContents.isEmpty() || checkSumContents.size() > 1)
        {
            logger.error(String.format("Found illegal checksum contents for [%s]", path));
            return null;
        }
        
        String checkSumStr = checkSumContents.iterator().next();
        
        return checkSumStr;
    }

    @Override
    public Nuspec getNuspec()
        throws NugetFormatException
    {
        return nuspecFile;
    }

    private Nuspec createNuspecFile()
        throws NugetFormatException
    {
        RepositoryPath nuspecPath = path.resolveSibling(artifactCoordinates.getId() + ".nuspec");
        if (!Files.exists(nuspecPath))
        {
            logger.trace(String.format("Failed to resolve .nuspec file for [%s]", path));
            Nuspec result = new Nuspec();
            Metadata metadata = result.getMetadata();
            metadata.id = artifactCoordinates.getId();
            metadata.version = SemanticVersion.parse(artifactCoordinates.getVersion());
            metadata.title = metadata.id;
            return result;
        }
        
        try
        {
            return Nuspec.parse(Files.newInputStream(nuspecPath));
        }
        catch (IOException e)
        {
            logger.error(String.format("Failed to read .nuspec file for [%s]", path), e);
            return null;
        }
    }

    @Override
    public Long getSize()
    {
        try
        {
            return path.getArtifactEntry().getSizeInBytes();
        }
        catch (IOException e)
        {
            return 0L;
        }
    }

    @Override
    public InputStream getStream()
        throws IOException
    {
        return Files.newInputStream(path);
    }

    @Override
    public Date getUpdated()
    {
        try
        {
            return path.getArtifactEntry().getLastUpdated();
        }
        catch (IOException e)
        {
            return null;
        }
    }

    @Override
    public String getId()
    {
        return artifactCoordinates.getId();
    }

    @Override
    public SemanticVersion getVersion()
    {
        try
        {
            return SemanticVersion.parse(artifactCoordinates.getVersion());
        }
        catch (Exception e)
        {
            logger.error(String.format("Failed to parse version for [%s]", path));
            return null;
        }
    }

    @Override
    public boolean equals(Object obj)
    {
        if (!(obj instanceof PathNupkg)) {
            return false;
        }
        return path.equals(((PathNupkg)obj).path);
    }

    @Override
    public int hashCode()
    {
        return path.hashCode();
    }

}

@@ -2429,58 +2429,10 @@
 urn 
-DatatypeConverter.printBase64Binary(new byte%5B%5D %7B%7D)
+%22%22
 ;%0A  

Remove redundant call for base64 conversion