package flag_test

import (
	"testing"

	"github.com/spf13/viper"
	"github.com/stretchr/testify/assert"
	"go.uber.org/zap"
	"go.uber.org/zap/zaptest/observer"

	"github.com/aquasecurity/trivy/pkg/flag"
	"github.com/aquasecurity/trivy/pkg/log"
	"github.com/aquasecurity/trivy/pkg/types"
)

func TestScanFlagGroup_ToOptions(t *testing.T) {
	type fields struct {
		skipDirs       []string
		skipFiles      []string
		offlineScan    bool
		vulnType       string
		securityChecks string
	}
	tests := []struct {
		name     string
		args     []string
		fields   fields
		want     flag.ScanOptions
		wantLogs []string
	}{
		{
			name:   "happy path",
			args:   []string{"alpine:latest"},
			fields: fields{},
			want: flag.ScanOptions{
				Target: "alpine:latest",
			},
		},
		{
			name: "happy path for configs",
			args: []string{"alpine:latest"},
			fields: fields{
				securityChecks: "config",
			},
			want: flag.ScanOptions{
				Target:         "alpine:latest",
				SecurityChecks: []string{types.SecurityCheckConfig},
			},
		},
		{
			name: "with wrong security check",
			fields: fields{
				securityChecks: "vuln,WRONG-CHECK",
			},
			want: flag.ScanOptions{
				SecurityChecks: []string{types.SecurityCheckVulnerability},
			},
			wantLogs: []string{
				`unknown security check: WRONG-CHECK`,
			},
		},
		{
			name:   "without target (args)",
			args:   []string{},
			fields: fields{},
			want:   flag.ScanOptions{},
		},
		{
			name:   "with two or more targets (args)",
			args:   []string{"alpine:latest", "nginx:latest"},
			fields: fields{},
			want:   flag.ScanOptions{},
		},
		{
			name: "skip two files",
			fields: fields{
				skipFiles: []string{"file1", "file2"},
			},
			want: flag.ScanOptions{
				SkipFiles: []string{"file1", "file2"},
			},
		},
		{
			name: "skip two folders",
			fields: fields{
				skipDirs: []string{"dir1", "dir2"},
			},
			want: flag.ScanOptions{
				SkipDirs: []string{"dir1", "dir2"},
			},
		},
		{
			name: "offline scan",
			fields: fields{
				offlineScan: true,
			},
			want: flag.ScanOptions{
				OfflineScan: true,
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			level := zap.WarnLevel

			core, obs := observer.New(level)
			log.Logger = zap.New(core).Sugar()

			viper.Set(flag.SkipDirsFlag.ConfigName, tt.fields.skipDirs)
			viper.Set(flag.SkipFilesFlag.ConfigName, tt.fields.skipFiles)
			viper.Set(flag.OfflineScanFlag.ConfigName, tt.fields.offlineScan)
			viper.Set(flag.VulnTypeFlag.ConfigName, tt.fields.vulnType)
			viper.Set(flag.SecurityChecksFlag.ConfigName, tt.fields.securityChecks)

			// Assert options
			f := &flag.ScanFlagGroup{
				SkipDirs:       &flag.SkipDirsFlag,
				SkipFiles:      &flag.SkipFilesFlag,
				OfflineScan:    &flag.OfflineScanFlag,
				SecurityChecks: &flag.SecurityChecksFlag,
			}

			got := f.ToOptions(tt.args)
			assert.Equalf(t, tt.want, got, "ToOptions()")

			// Assert log messages
			var gotMessages []string
			for _, entry := range obs.AllUntimed() {
				gotMessages = append(gotMessages, entry.Message)
			}
			assert.Equal(t, tt.wantLogs, gotMessages, tt.name)
		})

	}
}
