# Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)

import re

import pytest

import spack.spec
from spack.oci.image import Digest, ImageReference, default_tag, tag


@pytest.mark.parametrize(
    "image_ref, expected",
    [
        (
            f"example.com:1234/a/b/c:tag@sha256:{'a'*64}",
            ("example.com:1234", "a/b/c", "tag", Digest.from_sha256("a" * 64)),
        ),
        ("example.com:1234/a/b/c:tag", ("example.com:1234", "a/b/c", "tag", None)),
        ("example.com:1234/a/b/c", ("example.com:1234", "a/b/c", "latest", None)),
        (
            f"example.com:1234/a/b/c@sha256:{'a'*64}",
            ("example.com:1234", "a/b/c", "latest", Digest.from_sha256("a" * 64)),
        ),
        # ipv4
        ("1.2.3.4:1234/a/b/c:tag", ("1.2.3.4:1234", "a/b/c", "tag", None)),
        # ipv6
        ("[2001:db8::1]:1234/a/b/c:tag", ("[2001:db8::1]:1234", "a/b/c", "tag", None)),
        # Follow docker rules for parsing
        ("ubuntu:22.04", ("index.docker.io", "library/ubuntu", "22.04", None)),
        ("myname/myimage:abc", ("index.docker.io", "myname/myimage", "abc", None)),
        ("myname:1234/myimage:abc", ("myname:1234", "myimage", "abc", None)),
        ("localhost/myimage:abc", ("localhost", "myimage", "abc", None)),
        ("localhost:1234/myimage:abc", ("localhost:1234", "myimage", "abc", None)),
    ],
)
def test_name_parsing(image_ref, expected):
    x = ImageReference.from_string(image_ref)
    assert (x.domain, x.name, x.tag, x.digest) == expected


@pytest.mark.parametrize(
    "image_ref",
    [
        # wrong order of tag and sha
        f"example.com:1234/a/b/c@sha256:{'a'*64}:tag",
        # double tag
        "example.com:1234/a/b/c:tag:tag",
        # empty tag
        "example.com:1234/a/b/c:",
        # empty digest
        "example.com:1234/a/b/c@sha256:",
        # unsupport digest algorithm
        f"example.com:1234/a/b/c@sha512:{'a'*128}",
        # invalid digest length
        f"example.com:1234/a/b/c@sha256:{'a'*63}",
        # whitespace
        "example.com:1234/a/b/c :tag",
        "example.com:1234/a/b/c: tag",
        "example.com:1234/a/b/c:tag ",
        " example.com:1234/a/b/c:tag",
        # broken ipv4
        "1.2..3:1234/a/b/c:tag",
    ],
)
def test_parsing_failure(image_ref):
    with pytest.raises(ValueError):
        ImageReference.from_string(image_ref)


def test_digest():
    valid_digest = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"

    # Test string roundtrip
    assert str(Digest.from_string(f"sha256:{valid_digest}")) == f"sha256:{valid_digest}"

    # Invalid digest length
    with pytest.raises(ValueError):
        Digest.from_string("sha256:abcdef")

    # Missing algorithm
    with pytest.raises(ValueError):
        Digest.from_string(valid_digest)


@pytest.mark.parametrize(
    "spec",
    [
        # Standard case
        "short-name@=1.2.3",
        # Unsupported characters in git version
        f"git-version@{1:040x}=develop",
        # Too long of a name
        f"{'too-long':x<256}@=1.2.3",
    ],
)
def test_default_tag(spec: str):
    """Make sure that computed image tags are valid."""
    assert re.fullmatch(tag, default_tag(spack.spec.Spec(spec)))
