package unmarshal

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func Test_OSFixedIns_FilterToHighestModularity(t *testing.T) {

	keepAll := []OSFixedIn{
		{
			Module:        nil,
			Name:          "name",
			NamespaceName: "namespace",
			Version:       "v1.0.2",
			VersionFormat: "semver",
		},
		{
			Module: func() *string {
				x := ""
				return &x
			}(),
			Name:          "name",
			NamespaceName: "namespace",
			Version:       "v1.0.2",
			VersionFormat: "semver",
		},
	}

	table := []struct {
		name   string
		start  OSFixedIns
		expect OSFixedIns
	}{
		{
			name:   "go case: no filtering",
			start:  keepAll,
			expect: keepAll,
		},
		{
			name: "keep the highest version of a module",
			start: []OSFixedIn{
				{
					Module: func() *string {
						x := "name:1.0.2"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.2",
					VersionFormat: "semver",
				},
				{
					Module: func() *string {
						x := "name:1.0.3"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.3",
					VersionFormat: "semver",
				},
			},
			expect: []OSFixedIn{
				{
					Module: func() *string {
						x := "name:1.0.3"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.3",
					VersionFormat: "semver",
				},
			},
		},
		{
			name: "keep the highest version of a module (version processing flipped)",
			start: []OSFixedIn{

				{
					Module: func() *string {
						x := "name:1.0.3"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.3",
					VersionFormat: "semver",
				},
				{
					Module: func() *string {
						x := "name:1.0.2"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.2",
					VersionFormat: "semver",
				},
			},
			expect: []OSFixedIn{
				{
					Module: func() *string {
						x := "name:1.0.3"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.3",
					VersionFormat: "semver",
				},
			},
		},
		{
			name: "keep distinct module names (even though the package info is the same)",
			start: []OSFixedIn{
				{
					Module: func() *string {
						x := "name-1:1.0.2" // <-- important
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.2",
					VersionFormat: "semver",
				},
				{
					Module: func() *string {
						x := "name:1.0.3"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.3",
					VersionFormat: "semver",
				},
			},
			expect: []OSFixedIn{
				{
					Module: func() *string {
						x := "name:1.0.3"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.3",
					VersionFormat: "semver",
				},
				{
					Module: func() *string {
						x := "name-1:1.0.2"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.2",
					VersionFormat: "semver",
				},
			},
		},
		{
			name: "keep distinct namespaces",
			start: []OSFixedIn{
				{
					Module: func() *string {
						x := "name:1.0.2"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace-1", // <-- important
					Version:       "v1.0.2",
					VersionFormat: "semver",
				},
				{
					Module: func() *string {
						x := "name:1.0.3"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.3",
					VersionFormat: "semver",
				},
			},
			expect: []OSFixedIn{
				{
					Module: func() *string {
						x := "name:1.0.2"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace-1",
					Version:       "v1.0.2",
					VersionFormat: "semver",
				},
				{
					Module: func() *string {
						x := "name:1.0.3"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.3",
					VersionFormat: "semver",
				},
			},
		},
		{
			name: "keep module with no numeric versions",
			start: []OSFixedIn{
				{
					Module: func() *string {
						x := "name:prefix1.0.2" // <-- important
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.2",
					VersionFormat: "semver",
				},
				{
					Module: func() *string {
						x := "name:1.0.3"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.3",
					VersionFormat: "semver",
				},
			},
			expect: []OSFixedIn{
				{
					Module: func() *string {
						x := "name:prefix1.0.2"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.2",
					VersionFormat: "semver",
				},
				{
					Module: func() *string {
						x := "name:1.0.3"
						return &x
					}(),
					Name:          "name",
					NamespaceName: "namespace",
					Version:       "v1.0.3",
					VersionFormat: "semver",
				},
			},
		},
	}

	for _, tt := range table {
		t.Run(tt.name, func(t *testing.T) {
			got := tt.start.FilterToHighestModularity()
			assert.Equal(t, tt.expect, got)
		})
	}
}
