package query

import (
	"testing"

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

func TestGeneralLogsTableName(t *testing.T) {
	assert.Equal(t, "general_logs_us_west_2", generalLogsTableName("us-west-2", ""))
	assert.Equal(t, "general_logs_us_west_2_staging", generalLogsTableName("us-west-2", "staging"))
	assert.Equal(t, "general_logs_us_east_1", generalLogsTableName("us-east-1", ""))
	assert.Equal(t, "general_logs_us_east_1_serverless", generalLogsTableName("us-east-1-serverless", ""))
	assert.Equal(t, "general_logs_ap_southeast_2_ng", generalLogsTableName("ap-southeast-2-ng", ""))
}

func TestLogicalRegionFromBucket(t *testing.T) {
	assert.Equal(t, "us-east-1-serverless", logicalRegionFromBucket("o11y-prod-shared-us-east-1-serverless"))
	assert.Equal(t, "us-east-1", logicalRegionFromBucket("o11y-prod-shared-us-east-1"))
	assert.Equal(t, "ap-southeast-2-ng", logicalRegionFromBucket("o11y-prod-shared-ap-southeast-2-ng"))
	assert.Equal(t, "us-west-2-byoc-1128", logicalRegionFromBucket("o11y-dev-shared-us-west-2-byoc-1128"))
	assert.Equal(t, "", logicalRegionFromBucket("other-bucket"))
}

func TestResolveRegistryTables(t *testing.T) {
	tables := resolveRegistryTables(Config{
		Region:     "us-east-1",
		LogsBucket: "o11y-prod-shared-us-east-1-serverless",
	})
	require.Len(t, tables, 12)
	assert.Equal(t, "o11y-logs", tables[0].Database)
	assert.Equal(t, "general_logs_us_east_1_serverless", tables[0].Name)
	assert.Equal(t, DatasetLogs, tables[0].Definition.Dataset)
	assert.Equal(t, "s3://o11y-prod-shared-us-east-1-serverless/deltalake/global/logs/", tables[0].Location)
	assert.Contains(t, tables[0].Definition.PartitionProjection["storage.location.template"],
		"component=${component}/")

	assert.Equal(t, "log_stats_us_east_1_serverless", tables[1].Name)
	assert.Equal(t, DatasetLogStats, tables[1].Definition.Dataset)
	assert.Equal(t, "s3://o11y-prod-shared-us-east-1-serverless/deltalake/global/log-stats/", tables[1].Location)
	assert.Contains(t, tables[1].Definition.PartitionProjection["storage.location.template"],
		"date=${date}/org=${org}/cluster=${cluster}/")
	assert.Equal(t, "bigint", tables[1].Definition.FileColumns[0].Type)      // hour
	assert.Equal(t, "string", tables[1].Definition.PartitionColumns[0].Type) // date

	assert.Equal(t, "topsql_us_east_1_serverless", tables[2].Name)
	assert.Equal(t, DatasetTopsql, tables[2].Definition.Dataset)
	assert.Equal(t, "s3://o11y-prod-shared-us-east-1-serverless/deltalake/", tables[2].Location)
	assert.Contains(t, tables[2].Definition.PartitionProjection["storage.location.template"],
		"type=topsql/component=${component}/instance=${instance}/date=${date}/")

	assert.Equal(t, "topsql_sql_meta_us_east_1_serverless", tables[3].Name)
	assert.Equal(t, DatasetTopsqlSQLMeta, tables[3].Definition.Dataset)
	assert.Contains(t, tables[3].Definition.PartitionProjection["storage.location.template"],
		"component=topsql_sql_meta")

	assert.Equal(t, "topsql_plan_meta_us_east_1_serverless", tables[4].Name)
	assert.Equal(t, DatasetTopsqlPlanMeta, tables[4].Definition.Dataset)
	assert.Contains(t, tables[4].Definition.PartitionProjection["storage.location.template"],
		"component=topsql_plan_meta")

	assert.Equal(t, "topru_us_east_1_serverless", tables[5].Name)
	assert.Equal(t, DatasetTopru, tables[5].Definition.Dataset)
	assert.Contains(t, tables[5].Definition.PartitionProjection["storage.location.template"],
		"component=topru/instance=default/date=${date}/")

	assert.Equal(t, "sqlstatement_us_east_1_serverless", tables[6].Name)
	assert.Equal(t, DatasetSQLStatement, tables[6].Definition.Dataset)
	assert.Contains(t, tables[6].Definition.PartitionProjection["storage.location.template"],
		"type=sqlstatement/component=sqlstatement/date=${date}/")

	assert.Equal(t, "slowlogs_us_east_1_serverless", tables[7].Name)
	assert.Equal(t, DatasetSlowlogs, tables[7].Definition.Dataset)
	assert.Contains(t, tables[7].Definition.PartitionProjection["storage.location.template"],
		"deltalake/${org}/${cluster}/slowlogs/date=${date}")
	assert.Equal(t, "integer", tables[7].Definition.PartitionProjection["projection.date.type"])
	assert.NotContains(t, tables[7].Definition.PartitionProjection["storage.location.template"],
		"type=slowlog")

	assert.Equal(t, "metrics_status_sources_us_east_1_serverless", tables[8].Name)
	assert.Equal(t, DatasetMetricsStatusSources, tables[8].Definition.Dataset)
	assert.Contains(t, tables[8].Definition.PartitionProjection["storage.location.template"],
		"metrics-status/sources/biztype=${biztype}/applicationID=${applicationid}/date=${date}/")
	assert.Equal(t, "injected", tables[8].Definition.PartitionProjection["projection.applicationid.type"])
	assert.Equal(t, "string", tables[8].Definition.FileColumns[0].Type) // accountID

	assert.Equal(t, "metrics_status_by_metric_name_us_east_1_serverless", tables[9].Name)
	assert.Equal(t, DatasetMetricsStatusByMetric, tables[9].Definition.Dataset)

	assert.Equal(t, "metrics_status_by_label_name_us_east_1_serverless", tables[10].Name)
	assert.Equal(t, DatasetMetricsStatusByLabel, tables[10].Definition.Dataset)

	assert.Equal(t, "metrics_status_by_label_value_pair_us_east_1_serverless", tables[11].Name)
	assert.Equal(t, DatasetMetricsStatusByLabelValue, tables[11].Definition.Dataset)
}

func TestLogStatsTableName(t *testing.T) {
	assert.Equal(t, "log_stats_us_east_1_serverless", logStatsTableName("us-east-1-serverless", ""))
	assert.Equal(t, "log_stats_us_west_2_staging", logStatsTableName("us-west-2", "staging"))
}

func TestMetricsStatusTableNames(t *testing.T) {
	assert.Equal(t, "metrics_status_sources_us_east_1_serverless", metricsStatusSourcesTableName("us-east-1-serverless", ""))
	assert.Equal(t, "metrics_status_by_metric_name_us_west_2_staging", metricsStatusByMetricTableName("us-west-2", "staging"))
}

func TestOrgClusterTableNames(t *testing.T) {
	assert.Equal(t, "topsql_us_west_2", topsqlTableName("us-west-2", ""))
	assert.Equal(t, "sqlstatement_us_east_1_serverless", sqlstatementTableName("us-east-1-serverless", ""))
	assert.Equal(t, "slowlogs_us_west_2_staging", slowlogsTableName("us-west-2", "staging"))
}

func TestExtractTableReferences(t *testing.T) {
	refs, err := ExtractTableReferences(
		"SELECT event_time FROM `o11y-logs`.general_logs_us_west_2 WHERE level = 'ERROR'",
		"o11y",
	)
	require.NoError(t, err)
	require.Len(t, refs, 1)
	assert.Equal(t, "o11y-logs", refs[0].Database)
	assert.Equal(t, "general_logs_us_west_2", refs[0].Table)
}

func TestFindResolvedTable(t *testing.T) {
	tables := resolveRegistryTables(Config{Region: "us-west-2", LogsBucket: "bucket"})
	got, ok := findResolvedTable(tables, "o11y-logs", "general_logs_us_west_2")
	require.True(t, ok)
	assert.Equal(t, "general_logs_us_west_2", got.Name)
}
