package precheckcatalog

import (
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/entity"
)

func TestNewItems(t *testing.T) {
	items := NewItems()
	require.Len(t, items, len(FeatureGapChecks)+len(MigrationReadinessChecks))
	keys := make(map[string]struct{}, len(items))
	featureCount := 0
	migrationReadinessCount := 0
	for _, item := range items {
		_, duplicate := keys[string(item.Category)+":"+item.CheckKey]
		require.False(t, duplicate)
		keys[string(item.Category)+":"+item.CheckKey] = struct{}{}
		require.Equal(t, entity.PrecheckItemExecutionStatePending, item.ExecutionState)
		require.NotEmpty(t, item.Why)
		switch item.Category {
		case entity.PrecheckCategoryFeatureGap:
			featureCount++
		case entity.PrecheckCategoryMigrationReadiness:
			migrationReadinessCount++
		}
	}
	require.Equal(t, 11, featureCount)
	require.Equal(t, 10, migrationReadinessCount)
}

func TestFeatureGapWhyMatchesSpec(t *testing.T) {
	expected := map[string]string{
		"customer_private_endpoint":   "Premium uses newly created private endpoints for the target instance by default. Applications using Dedicated private endpoints must switch to the new Premium private endpoints. Note: Seamless endpoint switch is a potential solution for customers who cannot update applications due to additional manual effort.",
		"vpc_peering":                 "Premium does not support VPC peering. Customers using Dedicated VPC peering must switch to Premium private endpoint connectivity.",
		"public_endpoint":             "Premium uses a different public endpoint from Dedicated. Applications using the Dedicated public endpoint must update connection configuration after migration.",
		"sql_port":                    "Premium uses SQL port 4000 by default. If the Dedicated cluster uses a custom SQL port, application connection configuration must be updated during migration.",
		"project_rbac":                "Migration execution requires sufficient permissions to create the target Premium instance and perform migration operations. The migration account should be Org owner, Project Owner or Instance Manager.",
		"cmek":                        "If Dedicated uses CMEK, the target Premium planning must include CMEK enablement and required KMS permissions for restore tasks.",
		"non_default_tidb_node_group": "Premium does not support TiDB node groups. Workload isolation that depends on TiDB node groups may need to be redesigned.",
		"audit_log_v1":                "Premium database audit logging is compatible with audit logging v2, but not with audit logging v1. Customers using v1 may need to change their audit log consumption process.",
		"changefeed_sink":             "Premium supports only specific changefeed downstream types. Unsupported downstreams may require customer confirmation and an alternative CDC plan.",
		"dedicated_api_usage":         "Dedicated API and Premium API are not equivalent. Dedicated uses the v1beta1 API, for example https://dedicated.tidbapi.com/v1beta1/clusters, while Premium uses the v1beta2 API, for example https://cloud.tidbapi.com/v1beta2/tidbs. API endpoints, resource models, and automation workflows may change after migration. If the customer uses Dedicated API for automation, existing scripts or integrations may fail after migrating to Premium.",
		"resource_pool_plan":          "Shared or isolated resource pool choice may affect cost, capacity planning, operational isolation, and customer impact. The decision should be made during migration planning with frontline, product, and engineering input.",
	}

	require.Len(t, FeatureGapChecks, len(expected))
	for _, check := range FeatureGapChecks {
		require.Equal(t, expected[check.Key], check.Why, check.Key)
	}
}

func TestFeatureGapTitleMatchesSpec(t *testing.T) {
	expected := map[string]string{
		"customer_private_endpoint":   "Private endpoint",
		"vpc_peering":                 "VPC peering",
		"public_endpoint":             "Public endpoint",
		"sql_port":                    "Custom port",
		"project_rbac":                "Project / RBAC",
		"cmek":                        "CMEK",
		"non_default_tidb_node_group": "TiDB node groups",
		"audit_log_v1":                "Database audit logging",
		"changefeed_sink":             "Changefeed compatibility",
		"dedicated_api_usage":         "Dedicated API",
		"resource_pool_plan":          "Resource pool",
	}

	require.Len(t, FeatureGapChecks, len(expected))
	for _, check := range FeatureGapChecks {
		require.Equal(t, expected[check.Key], check.Title, check.Key)
	}
}

func TestTablesWithoutValidIndexWhyMatchesSpec(t *testing.T) {
	const expected = "TiCDC only replicates tables that have at least one valid index to the downstream. " +
		"If an index in a table meets one of the following requirements, it is valid. A primary key (PRIMARY KEY) is a valid index. " +
		"A unique index (UNIQUE INDEX) is valid if every column of the index is explicitly defined as non-nullable (NOT NULL) " +
		"and the index does not have a virtual generated column (VIRTUAL GENERATED COLUMNS)."

	for _, check := range MigrationReadinessChecks {
		if check.Key == "tables_without_valid_index" {
			require.Equal(t, expected, check.Why)
			return
		}
	}
	t.Fatal("tables_without_valid_index migration readiness check not found")
}

func TestTTLMetadataMatchesSpec(t *testing.T) {
	const expectedWhy = "During migration, an Incremental Replication task is created to replicate changes from the Dedicated cluster to the Premium cluster. " +
		"To prevent duplicate TTL deletions, TTL_ENABLE is automatically set to OFF on the downstream tables, while TTL-triggered deletions " +
		"on the upstream cluster are replicated to the downstream cluster. After cutover, the customer must manually set TTL_ENABLE = 'ON' " +
		"on the Premium cluster for each table that has TTL configured. During rollback preparation, a reverse Incremental Replication task " +
		"is created to replicate changes from the Premium cluster back to the Dedicated cluster. To prevent TTL-triggered deletions from being " +
		"applied twice, the customer must disable TTL job execution on the Dedicated cluster before cutover."

	for _, check := range MigrationReadinessChecks {
		if check.Key == "ttl" {
			require.Equal(t, "TTL", check.Title)
			require.Equal(t, expectedWhy, check.Why)
			return
		}
	}
	t.Fatal("ttl migration readiness check not found")
}
