package api

import (
	"context"
	"os"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
	"github.com/tidbcloud/pkgv2/bizerr"
)

var (
	ctx = context.Background()
)

func Test_parseNodeAndSkuFiles(t *testing.T) {
	Convey("Test_parseNodeAndSkuFiles", t, func() {
		sku := &skuYaml{
			CloudProvider: "aws",
			Region:        "us-west-2",
			SkuType:       "node",
			Price:         "1",
			ResourceDetail: &resourceDetail{
				ComputeInstanceType: "r5.2xlarge",
				DeployType:          "dedicated",
			},
			skuExtra: skuExtra{},
		}
		Convey("simple", func() {
			skuFile, _ := os.Open("../test_data/profile/simple/skus.yaml")
			nodeFile, _ := os.Open("../test_data/profile/simple/nodes.yaml")
			skus := []*skuYaml{
				{CloudProvider: "aws",
					Region:  "us-west-2",
					SkuType: SkuType("node"),
					Price:   "1.8",
					ResourceDetail: &resourceDetail{
						ComputeInstanceType: "r5.2xlarge",
						DeployType:          "dedicated",
						DiskInstanceType:    "",
					},
				},
				{
					CloudProvider: "aws",
					Region:        "us-west-2",
					SkuType:       SkuType("disk-iops"),
					Price:         "1.8",
					ResourceDetail: &resourceDetail{
						ComputeInstanceType: "",
						DeployType:          "",
						DiskInstanceType:    "gp3",
					},
				},
				{
					CloudProvider: "aws",
					Region:        "us-west-2",
					SkuType:       SkuType("disk-throughput"),
					Price:         "1.8",
					ResourceDetail: &resourceDetail{
						ComputeInstanceType: "",
						DeployType:          "",
						DiskInstanceType:    "gp3",
					},
				},
				{
					CloudProvider: "aws",
					Region:        "us-west-2",
					SkuType:       SkuType("disk-storage"),
					Price:         "1.8",
					ResourceDetail: &resourceDetail{
						ComputeInstanceType: "",
						DeployType:          "",
						DiskInstanceType:    "gp3",
					},
				},
			}
			nodes := []*nodeYaml{
				{
					ComponentType: "tikv",
					CloudProvider: "aws",
					Regions:       []string{"us-west-2"},
					NonStandardCustomers: []*tenantInfo{
						{TenantId: 84362, TenantName: "apple"},
					},
					Annotation: "t3.standard",
					Node: &nodeDetail{
						Name:           "8 vCPU",
						InstanceType:   "r5.2xlarge",
						DeployType:     "dedicated",
						CpuNum:         8,
						MemoryGi:       16,
						DefaultNodeNum: 1,
						Disk: &nodeDisk{
							InstanceType: "gp3",
							Iops:         1000,
							ThroughputMi: 300,
							MinSizeGi:    500,
							MaxSizeGi:    2048,
						},
					},
				},
			}

			r1, r2, err := parseNodeAndSkuFiles(ctx, skuFile, nodeFile)
			So(err, ShouldBeNil)
			So(r1, ShouldResemble, skus)
			So(r2, ShouldResemble, nodes)
		})
		Convey("full", func() {
			skuFile, _ := os.Open("../test_data/profile/full/skus.yaml")
			nodeFile, _ := os.Open("../test_data/profile/full/nodes.yaml")

			_, _, err := parseNodeAndSkuFiles(ctx, skuFile, nodeFile)
			So(err, ShouldBeNil)
		})
		Convey("sku.resourceDetail", func() {
			Convey("normal case", func() {
				err := validateNodesAndSkus(ctx, nil, []*skuYaml{sku})
				So(err, ShouldBeNil)
			})
			Convey("should return err if resourceDetail is nil", func() {
				sku.ResourceDetail = nil

				err := validateNodesAndSkus(ctx, nil, []*skuYaml{sku})
				So(err, ShouldNotBeNil)
			})
			Convey("should return err if diskInstanceType is empty but resourceType is disk-XXX", func() {
				for _, each := range []SkuType{SkuTypeDiskIops, SkuTypeDiskThroughput, SkuTypeDiskStorage} {
					sku.SkuType = each
					err := validateNodesAndSkus(ctx, nil, []*skuYaml{sku})
					So(err, ShouldNotBeNil)
					So(err.RawErrCode(), ShouldEqual, bizerr.ErrCodeParams)
				}
			})
			Convey("should return err if instanceType is empty and resourceType is node", func() {
				sku.ResourceDetail.ComputeInstanceType = ""
				err := validateNodesAndSkus(ctx, nil, []*skuYaml{sku})
				So(err, ShouldNotBeNil)
				So(err.RawErrCode(), ShouldEqual, bizerr.ErrCodeParams)
			})
			Convey("should return err if topology is empty and resourceType is node", func() {
				sku.ResourceDetail.DeployType = ""
				err := validateNodesAndSkus(ctx, nil, []*skuYaml{sku})
				So(err, ShouldNotBeNil)
				So(err.RawErrCode(), ShouldEqual, bizerr.ErrCodeParams)
			})
		})
	})
}
