package task

import (
	"context"
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
	storagev1 "k8s.io/api/storage/v1"
	"k8s.io/apimachinery/pkg/api/resource"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/config"
)

type fakeCloudConfigProvider struct {
	instanceTypes map[string]cloudv1.InstanceType
	err           error
}

func (f *fakeCloudConfigProvider) GetProviderType() string {
	return "test"
}

func (f *fakeCloudConfigProvider) GetInstanceTypes() ([]cloudv1.InstanceType, error) {
	if f.err != nil {
		return nil, f.err
	}

	result := make([]cloudv1.InstanceType, 0, len(f.instanceTypes))
	for _, it := range f.instanceTypes {
		result = append(result, it)
	}
	return result, nil
}

func (f *fakeCloudConfigProvider) GetStorageClasses() ([]*storagev1.StorageClass, error) {
	return nil, nil
}

func (f *fakeCloudConfigProvider) FindInstanceType(name string) (cloudv1.InstanceType, error) {
	if f.err != nil {
		return cloudv1.InstanceType{}, f.err
	}

	it, ok := f.instanceTypes[name]
	if !ok {
		return cloudv1.InstanceType{}, fmt.Errorf("instance type %q not found", name)
	}
	return it, nil
}

func (f *fakeCloudConfigProvider) FindRegionZones(region string) ([]string, error) {
	return nil, nil
}

func TestGetPhysicalFileCacheCapacity(t *testing.T) {
	tests := map[string]struct {
		cfg          *fakeCloudConfigProvider
		instanceType string
		want         string
	}{
		"configured when memory above threshold": {
			cfg: &fakeCloudConfigProvider{
				instanceTypes: map[string]cloudv1.InstanceType{
					"test.2xlarge": {
						Name:   "test.2xlarge",
						Memory: resource.MustParse("256Gi"),
					},
				},
			},
			instanceType: "test.2xlarge",
			want:         "150G",
		},
		"configured when memory equals threshold": {
			cfg: &fakeCloudConfigProvider{
				instanceTypes: map[string]cloudv1.InstanceType{
					"test.xlarge": {
						Name:   "test.xlarge",
						Memory: resource.MustParse("230Gi"),
					},
				},
			},
			instanceType: "test.xlarge",
			want:         "124G",
		},
		"not configured when memory below threshold": {
			cfg: &fakeCloudConfigProvider{
				instanceTypes: map[string]cloudv1.InstanceType{
					"test.large": {
						Name:   "test.large",
						Memory: resource.MustParse("229Gi"),
					},
				},
			},
			instanceType: "test.large",
			want:         "",
		},
		"not configured when instance type missing": {
			cfg: &fakeCloudConfigProvider{
				instanceTypes: map[string]cloudv1.InstanceType{},
			},
			instanceType: "not-exist",
			want:         "",
		},
		"not configured when config missing": {
			cfg:          nil,
			instanceType: "test.xlarge",
			want:         "",
		},
	}

	for name, tt := range tests {
		t.Run(name, func(t *testing.T) {
			var cfg config.CloudConfigProvider
			if tt.cfg != nil {
				cfg = tt.cfg
			}

			task := &CompactTask{
				baseTask: &baseTask{
					Context: &Context{
						config: cfg,
					},
				},
			}

			got := task.getPhysicalFileCacheCapacity(context.Background(), tt.instanceType)
			assert.Equal(t, tt.want, got)
		})
	}
}
