package rcuquota

import (
	"testing"

	"github.com/stretchr/testify/assert"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/infra/repoimpl/schema"
)

func uint32Ptr(v uint32) *uint32 {
	return &v
}

func TestSchemaToEntity(t *testing.T) {
	tests := []struct {
		name     string
		model    *schema.RcuQuota
		expected *entity.RcuQuota
	}{
		// 1. Normal Case: Standard values and 20% burst (1.2 multiplier)
		{
			name: "Normal_Case_20_Percent",
			model: &schema.RcuQuota{
				TenantID:                  1001,
				Quota:                     80000,
				TotalMaxRCU:               100000,
				BurstAllowancePercent:     uint32Ptr(20), // 20%
				VcpusLimitPerResourcePool: 400,
			},
			expected: &entity.RcuQuota{
				OrganizationId:            1001,
				InstanceMaxRcu:            80000,
				TotalMaxRcu:               100000,
				BurstyRatio:               1.2, // (20 + 100) / 100 = 1.2
				BustyRatio:                1.2, // always equal to BurstyRatio
				VcpusLimitPerResourcePool: 400,
			},
		},
		// 2. Zero Burst: 0% burst (1.0 multiplier)
		{
			name: "Zero_Burst_Case",
			model: &schema.RcuQuota{
				TenantID:              1002,
				Quota:                 1000,
				TotalMaxRCU:           2000,
				BurstAllowancePercent: uint32Ptr(0), // 0%
			},
			expected: &entity.RcuQuota{
				OrganizationId: 1002,
				InstanceMaxRcu: 1000,
				TotalMaxRcu:    2000,
				BurstyRatio:    1.0, // (0 + 100) / 100 = 1.0
				BustyRatio:     1.0, // always equal to BurstyRatio
			},
		},
		// 3. High Burst: 500% burst (6.0 multiplier)
		{
			name: "High_Burst_Case_500_Percent",
			model: &schema.RcuQuota{
				TenantID:              1003,
				Quota:                 1,
				TotalMaxRCU:           1,
				BurstAllowancePercent: uint32Ptr(500), // 500%
			},
			expected: &entity.RcuQuota{
				OrganizationId: 1003,
				InstanceMaxRcu: 1,
				TotalMaxRcu:    1,
				BurstyRatio:    6.0, // (500 + 100) / 100 = 6.0
				BustyRatio:     6.0, // (500 + 100) / 100 = 6.0
			},
		},
		// 4. Nil Input: Should return a zero-valued entity
		{
			name:     "Nil_Input",
			model:    nil,
			expected: &entity.RcuQuota{},
		},
		{
			name: "Nil_BurstAllowancePercent_Defaults_To_One",
			model: &schema.RcuQuota{
				TenantID:              1004,
				Quota:                 1000,
				TotalMaxRCU:           2000,
				BurstAllowancePercent: nil,
			},
			expected: &entity.RcuQuota{
				OrganizationId: 1004,
				InstanceMaxRcu: 1000,
				TotalMaxRcu:    2000,
				BurstyRatio:    1.0,
				BustyRatio:     1.0,
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Call the function to test (assuming it's named SchemaToEntity and exposed)
			actual := schemaToEntity(tt.model)

			// Assert that the actual result matches the expected result
			assert.Equal(t, tt.expected, actual)
		})
	}
}

func TestEntityToSchema(t *testing.T) {
	tests := []struct {
		name     string
		entity   *entity.RcuQuota
		expected *schema.RcuQuota
	}{
		// 1. Normal Case: 1.2 multiplier (20% burst)
		{
			name: "Normal_Case_1_point_2_Multiplier",
			entity: &entity.RcuQuota{
				OrganizationId:            2001,
				InstanceMaxRcu:            50000,
				TotalMaxRcu:               60000,
				BurstyRatio:               1.2, // 1.2
				BustyRatio:                1.2, // 1.2
				VcpusLimitPerResourcePool: 800,
			},
			expected: &schema.RcuQuota{
				TenantID:                  2001,
				Quota:                     50000,
				TotalMaxRCU:               60000,
				BurstAllowancePercent:     uint32Ptr(20), // (1.2 * 100) - 100 = 20
				ServicePlan:               globalcommonv1.ServicePlan_SERVICE_PLAN_UNSPECIFIED.String(),
				VcpusLimitPerResourcePool: 800,
			},
		},
		// 2. Zero Burst: 1.0 multiplier (0% burst)
		{
			name: "Zero_Burst_Case",
			entity: &entity.RcuQuota{
				OrganizationId: 2002,
				InstanceMaxRcu: 10,
				TotalMaxRcu:    20,
				BurstyRatio:    1.0, // 1.0
				ServicePlan:    globalcommonv1.ServicePlan_Premium,
			},
			expected: &schema.RcuQuota{
				TenantID:              2002,
				Quota:                 10,
				TotalMaxRCU:           20,
				BurstAllowancePercent: uint32Ptr(0), // (1.0 * 100) - 100 = 0
				ServicePlan:           globalcommonv1.ServicePlan_Premium.String(),
			},
		},
		// 3. High Multiplier: 6.0 multiplier (500% burst)
		{
			name: "High_Multiplier_Case_6_point_0",
			entity: &entity.RcuQuota{
				OrganizationId: 2003,
				InstanceMaxRcu: 1,
				TotalMaxRcu:    1,
				BurstyRatio:    6.0,
				ServicePlan:    globalcommonv1.ServicePlan_Premium,
			},
			expected: &schema.RcuQuota{
				TenantID:              2003,
				Quota:                 1,
				TotalMaxRCU:           1,
				BurstAllowancePercent: uint32Ptr(500), // (6.0 * 100) - 100 = 500
				ServicePlan:           globalcommonv1.ServicePlan_Premium.String(),
			},
		},
		// 4. Boundary Case: Float Precision (e.g., 1.2049 should round to 1.20)
		// We expect 1.2049 * 100 - 100 = 20.49. math.Round(20.49) = 20.
		// This tests the use of math.Round() in the conversion logic.
		{
			name: "Boundary_Case_Rounding_Down",
			entity: &entity.RcuQuota{
				OrganizationId: 2004,
				InstanceMaxRcu: 1000,
				TotalMaxRcu:    1000,
				BurstyRatio:    1.2049,
				ServicePlan:    globalcommonv1.ServicePlan_BYOC,
			},
			expected: &schema.RcuQuota{
				TenantID:              2004,
				Quota:                 1000,
				TotalMaxRCU:           1000,
				BurstAllowancePercent: uint32Ptr(20), // math.Round((1.2049 * 100) - 100) = math.Round(20.49) = 20
				ServicePlan:           globalcommonv1.ServicePlan_BYOC.String(),
			},
		},
		// 5. Boundary Case: Float Precision (e.g., 1.205 should round to 1.21)
		// We expect 1.205 * 100 - 100 = 20.5. math.Round(20.5) = 21.
		// This tests the use of math.Round() in the conversion logic.
		{
			name: "Boundary_Case_Rounding_Up",
			entity: &entity.RcuQuota{
				OrganizationId: 2005,
				InstanceMaxRcu: 1000,
				TotalMaxRcu:    1000,
				BurstyRatio:    1.205,
				ServicePlan:    globalcommonv1.ServicePlan_Premium,
			},
			expected: &schema.RcuQuota{
				TenantID:              2005,
				Quota:                 1000,
				TotalMaxRCU:           1000,
				BurstAllowancePercent: uint32Ptr(21), // math.Round((1.205 * 100) - 100) = math.Round(20.5) = 21
				ServicePlan:           globalcommonv1.ServicePlan_Premium.String(),
			},
		},
		// 6. Nil Input: Should return a zero-valued schema
		{
			name:     "Nil_Input",
			entity:   nil,
			expected: &schema.RcuQuota{},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Call the function to test (assuming it's named EntityToSchema and exposed)
			actual := entityToSchema(tt.entity)

			// Assert that the actual result matches the expected result
			assert.Equal(t, tt.expected, actual)
		})
	}
}
