package registry_test

import (
	"log/slog"
	"testing"

	"github.com/aquaproj/aqua/v2/pkg/config/registry"
	"github.com/aquaproj/aqua/v2/pkg/runtime"
	"github.com/google/go-cmp/cmp"
)

func TestPackageInfo_Override(t *testing.T) { //nolint:funlen
	t.Parallel()
	data := []struct {
		title   string
		exp     *registry.PackageInfo
		isErr   bool
		pkgInfo *registry.PackageInfo
		version string
		rt      *runtime.Runtime
	}{
		{
			title: "not override",
			pkgInfo: &registry.PackageInfo{
				Type:      pkgTypeGitHubRelease,
				RepoOwner: "suzuki-shunsuke",
				RepoName:  repoNameCiInfo,
				Asset:     "ci-info_{{.Arch}}-{{.OS}}.tar.gz",
				Replacements: registry.Replacements{
					"linux": "unknown-linux-musl",
				},
				Overrides: []*registry.Override{
					{
						GOOS:   "linux",
						GOArch: archArm64,
						Replacements: registry.Replacements{
							"linux": "unknown-linux-gnu",
						},
					},
				},
			},
			exp: &registry.PackageInfo{
				Type:      pkgTypeGitHubRelease,
				RepoOwner: "suzuki-shunsuke",
				RepoName:  repoNameCiInfo,
				Asset:     "ci-info_{{.Arch}}-{{.OS}}.tar.gz",
				Replacements: registry.Replacements{
					"linux": "unknown-linux-musl",
				},
				Overrides: []*registry.Override{
					{
						GOOS:   "linux",
						GOArch: archArm64,
						Replacements: registry.Replacements{
							"linux": "unknown-linux-gnu",
						},
					},
				},
			},
			version: "v1.0.0",
			rt: &runtime.Runtime{
				GOOS:   osDarwin,
				GOARCH: archAmd64,
			},
		},
		{
			title: "override",
			pkgInfo: &registry.PackageInfo{
				Type:      pkgTypeGitHubRelease,
				RepoOwner: "suzuki-shunsuke",
				RepoName:  repoNameCiInfo,
				Asset:     "ci-info_{{.Arch}}-{{.OS}}.tar.gz",
				Replacements: registry.Replacements{
					"linux": "unknown-linux-musl",
				},
				Overrides: []*registry.Override{
					{
						GOOS:   "linux",
						GOArch: archArm64,
						Replacements: registry.Replacements{
							"linux": "unknown-linux-gnu",
						},
					},
				},
			},
			exp: &registry.PackageInfo{
				Type:      pkgTypeGitHubRelease,
				RepoOwner: "suzuki-shunsuke",
				RepoName:  repoNameCiInfo,
				Asset:     "ci-info_{{.Arch}}-{{.OS}}.tar.gz",
				Replacements: registry.Replacements{
					"linux": "unknown-linux-gnu",
				},
				Overrides: []*registry.Override{
					{
						GOOS:   "linux",
						GOArch: archArm64,
						Replacements: registry.Replacements{
							"linux": "unknown-linux-gnu",
						},
					},
				},
			},
			version: "v1.0.0",
			rt: &runtime.Runtime{
				GOOS:   "linux",
				GOARCH: archArm64,
			},
		},
	}
	logger := slog.New(slog.DiscardHandler)
	for _, d := range data {
		t.Run(d.title, func(t *testing.T) {
			t.Parallel()
			pkgInfo, err := d.pkgInfo.Override(logger, d.version, d.rt)
			if err != nil {
				if d.isErr {
					return
				}
				t.Fatal(err)
			}
			if d.isErr {
				t.Fatal("error must be returned")
			}
			if diff := cmp.Diff(d.exp, pkgInfo); diff != "" {
				t.Fatal(diff)
			}
		})
	}
}

func TestOverride_Match(t *testing.T) { //nolint:funlen
	t.Parallel()
	data := []struct {
		title    string
		exp      bool
		override *registry.Override
		rt       *runtime.Runtime
	}{
		{
			title: "goos doesn't match",
			override: &registry.Override{
				GOOS: "linux",
			},
			rt: &runtime.Runtime{
				GOOS:   osDarwin,
				GOARCH: archAmd64,
			},
		},
		{
			title: "goarch doesn't match",
			override: &registry.Override{
				GOArch: archArm64,
			},
			rt: &runtime.Runtime{
				GOOS:   osDarwin,
				GOARCH: archAmd64,
			},
		},
		{
			title: "match",
			exp:   true,
			override: &registry.Override{
				GOOS: osDarwin,
			},
			rt: &runtime.Runtime{
				GOOS:   osDarwin,
				GOARCH: archAmd64,
			},
		},
		{
			title: "variant libc musl matches",
			exp:   true,
			override: &registry.Override{
				GOOS: "linux",
				Variants: registry.Variants{
					{Key: "libc", Value: "musl"},
				},
			},
			rt: &runtime.Runtime{
				GOOS:   "linux",
				GOARCH: archAmd64,
				LibC:   "musl",
			},
		},
		{
			title: "variant libc musl doesn't match glibc runtime",
			override: &registry.Override{
				GOOS: "linux",
				Variants: registry.Variants{
					{Key: "libc", Value: "musl"},
				},
			},
			rt: &runtime.Runtime{
				GOOS:   "linux",
				GOARCH: archAmd64,
				LibC:   "glibc",
			},
		},
		{
			title: "variant libc constraint with empty runtime libc doesn't match",
			override: &registry.Override{
				GOOS: "linux",
				Variants: registry.Variants{
					{Key: "libc", Value: "musl"},
				},
			},
			rt: &runtime.Runtime{
				GOOS:   "linux",
				GOARCH: archAmd64,
			},
		},
		{
			title: "unknown variant key skips the override",
			override: &registry.Override{
				GOOS: "linux",
				Variants: registry.Variants{
					{Key: "cpu", Value: "avx2"},
				},
			},
			rt: &runtime.Runtime{
				GOOS:   "linux",
				GOARCH: archAmd64,
				LibC:   "glibc",
			},
		},
		{
			title: "all variants must match",
			override: &registry.Override{
				GOOS: "linux",
				Variants: registry.Variants{
					{Key: "libc", Value: "musl"},
					{Key: "libc", Value: "glibc"},
				},
			},
			rt: &runtime.Runtime{
				GOOS:   "linux",
				GOARCH: archAmd64,
				LibC:   "musl",
			},
		},
	}
	for _, d := range data {
		t.Run(d.title, func(t *testing.T) {
			t.Parallel()
			if f := d.override.Match(d.rt); f != d.exp {
				t.Fatalf("wanted %v, got %v", d.exp, f)
			}
		})
	}
}
