package util

import (
	"testing"

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

func TestPareseAWSLBName(t *testing.T) {
	cases := []struct {
		in  string
		out string
		err bool
	}{
		{"k8s-foo-bar-1234567890.us-west-2.elb.amazonaws.com", "k8s-foo-bar", false},
		{"k8s-foo-bar-1234567890.us-east-2.elb.amazonaws.com", "k8s-foo-bar", false},
		{"aa.us-east-2.elb.amazonaws.com", "", true},
	}

	for _, c := range cases {
		got, err := PareseAWSLBName(c.in)
		if c.err {
			require.NotNil(t, err)
		} else {
			require.Nil(t, err)
		}

		require.Equal(t, c.out, got)
	}
}

func TestPolicyDocumentToString(t *testing.T) {
	tests := []struct {
		name    string
		doc     *PolicyDocument
		want    string
		wantErr bool
	}{
		{
			name: "basic policy document",
			doc: &PolicyDocument{
				Version: "2012-10-17",
				Statement: []*PolicyStatement{
					{
						Effect:   "Allow",
						Action:   []string{"s3:GetObject"},
						Resource: []string{"arn:aws:s3:::bucket/*"},
					},
				},
			},
			want:    `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:GetObject"],"Resource":["arn:aws:s3:::bucket/*"]}]}`,
			wantErr: false,
		},
		{
			name: "policy with principal",
			doc: &PolicyDocument{
				Version: "2012-10-17",
				Statement: []*PolicyStatement{
					{
						Effect: "Allow",
						Principal: &PolicyPrincipal{
							AWS: []string{"arn:aws:iam::123456789012:root"},
						},
						Action: []string{"sts:AssumeRole"},
					},
				},
			},
			want:    `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["sts:AssumeRole"],"Principal":{"AWS":["arn:aws:iam::123456789012:root"]}}]}`,
			wantErr: false,
		},
		{
			name:    "empty policy document",
			doc:     &PolicyDocument{},
			want:    `{"Version":"","Statement":null}`,
			wantErr: false,
		},
		{
			name:    "nil policy document",
			doc:     nil,
			want:    "",
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := tt.doc.ToString()
			if (err != nil) != tt.wantErr {
				t.Errorf("PolicyDocument.ToString() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			assert.Equal(t, tt.want, got)
		})
	}
}

func TestPolicyStatementAppendResource(t *testing.T) {
	tests := []struct {
		name     string
		stmt     *PolicyStatement
		resource string
		want     []string
	}{
		{
			name: "append new resource",
			stmt: &PolicyStatement{
				Resource: []string{"arn:aws:s3:::bucket1"},
			},
			resource: "arn:aws:s3:::bucket2",
			want:     []string{"arn:aws:s3:::bucket1", "arn:aws:s3:::bucket2"},
		},
		{
			name: "append duplicate resource",
			stmt: &PolicyStatement{
				Resource: []string{"arn:aws:s3:::bucket1"},
			},
			resource: "arn:aws:s3:::bucket1",
			want:     []string{"arn:aws:s3:::bucket1"},
		},
		{
			name: "append to empty resource list",
			stmt: &PolicyStatement{
				Resource: []string{},
			},
			resource: "arn:aws:s3:::bucket1",
			want:     []string{"arn:aws:s3:::bucket1"},
		},
		{
			name:     "append to nil resource list",
			stmt:     &PolicyStatement{},
			resource: "arn:aws:s3:::bucket1",
			want:     []string{"arn:aws:s3:::bucket1"},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.stmt.AppendResource(tt.resource)
			assert.Equalf(t, tt.want, tt.stmt.Resource, "AppendResource() got = %v, want %v", tt.stmt.Resource, tt.want)
		})
	}
}
