package query

import "fmt"

const (
	metricsStatusDataPathSuffix = "deltalake/global/metrics-status/"

	DatasetMetricsStatusSources      = "metrics-status"
	DatasetMetricsStatusSourcesAlias = "metrics_status_sources"
	metricsStatusSourcesBase         = "metrics_status_sources"

	DatasetMetricsStatusByMetric      = "metrics-status-by-metric"
	DatasetMetricsStatusByMetricAlias = "metrics_status_by_metric_name"
	metricsStatusByMetricBase         = "metrics_status_by_metric_name"

	DatasetMetricsStatusByLabel      = "metrics-status-by-label"
	DatasetMetricsStatusByLabelAlias = "metrics_status_by_label_name"
	metricsStatusByLabelBase         = "metrics_status_by_label_name"

	DatasetMetricsStatusByLabelValue      = "metrics-status-by-label-value"
	DatasetMetricsStatusByLabelValueAlias = "metrics_status_by_label_value_pair"
	metricsStatusByLabelValueBase         = "metrics_status_by_label_value_pair"
)

func metricsStatusPartitionColumns() []ColumnMeta {
	return []ColumnMeta{
		{Name: "biztype", Type: "string"},
		{Name: "applicationID", Type: "string", Description: "TiDB Cloud application / cluster ID"},
		{Name: "date", Type: "string", Description: "UTC date as yyyyMMdd"},
	}
}

func metricsStatusAccountIDColumn() ColumnMeta {
	// Writer emits accountID as string; Glue uses varchar for cross-region Parquet compatibility.
	return ColumnMeta{Name: "accountID", Type: "string", Description: "VictoriaMetrics account ID"}
}

func metricsStatusPartitionProjection() map[string]string {
	return map[string]string{
		"projection.enabled":            "true",
		"projection.biztype.type":       "injected",
		"projection.applicationid.type": "injected",
		"projection.date.type":          "integer",
		"projection.date.range":         "20240101,20991231",
		"projection.date.digits":        "8",
		"classification":                "parquet",
		"EXTERNAL":                      "TRUE",
	}
}

func metricsStatusSourcesTableDef() TableDefinition {
	return TableDefinition{
		ID:            metricsStatusSourcesBase,
		Dataset:       DatasetMetricsStatusSources,
		Description:   "VM TSDB status summary per cluster/day under deltalake/global/metrics-status/sources/",
		RequiresScope: true,
		FileColumns: []ColumnMeta{
			metricsStatusAccountIDColumn(),
			{Name: "projectID", Type: "string", Description: "VictoriaMetrics project ID"},
			{Name: "tenantID", Type: "string", Description: "Tenant / org ID"},
			{Name: "isPartial", Type: "boolean"},
			{Name: "totalSeries", Type: "bigint"},
			{Name: "totalLabelValuePairs", Type: "bigint"},
		},
		PartitionColumns:    metricsStatusPartitionColumns(),
		PartitionProjection: metricsStatusPartitionProjection(),
	}
}

func metricsStatusByMetricTableDef() TableDefinition {
	return TableDefinition{
		ID:            metricsStatusByMetricBase,
		Dataset:       DatasetMetricsStatusByMetric,
		Description:   "VM TSDB series count by metric name under deltalake/global/metrics-status/series_count_by_metric_name/",
		RequiresScope: true,
		FileColumns: []ColumnMeta{
			metricsStatusAccountIDColumn(),
			{Name: "projectID", Type: "string"},
			{Name: "tenantID", Type: "string"},
			{Name: "name", Type: "string", Description: "Metric name"},
			{Name: "value", Type: "bigint", Description: "Series count"},
			{Name: "requestsCount", Type: "bigint", Description: "Optional request count (newer VM API)"},
			{Name: "lastRequestTimestamp", Type: "bigint", Description: "Optional last request unix seconds"},
		},
		PartitionColumns:    metricsStatusPartitionColumns(),
		PartitionProjection: metricsStatusPartitionProjection(),
	}
}

func metricsStatusByLabelTableDef() TableDefinition {
	return TableDefinition{
		ID:            metricsStatusByLabelBase,
		Dataset:       DatasetMetricsStatusByLabel,
		Description:   "VM TSDB series count by label name under deltalake/global/metrics-status/series_count_by_label_name/",
		RequiresScope: true,
		FileColumns: []ColumnMeta{
			metricsStatusAccountIDColumn(),
			{Name: "projectID", Type: "string"},
			{Name: "tenantID", Type: "string"},
			{Name: "name", Type: "string", Description: "Label name"},
			{Name: "value", Type: "bigint", Description: "Series count"},
		},
		PartitionColumns:    metricsStatusPartitionColumns(),
		PartitionProjection: metricsStatusPartitionProjection(),
	}
}

func metricsStatusByLabelValueTableDef() TableDefinition {
	return TableDefinition{
		ID:            metricsStatusByLabelValueBase,
		Dataset:       DatasetMetricsStatusByLabelValue,
		Description:   "VM TSDB series count by label value pair under deltalake/global/metrics-status/series_count_by_label_value_pair/",
		RequiresScope: true,
		FileColumns: []ColumnMeta{
			metricsStatusAccountIDColumn(),
			{Name: "projectID", Type: "string"},
			{Name: "tenantID", Type: "string"},
			{Name: "name", Type: "string", Description: "Label value pair key"},
			{Name: "value", Type: "bigint", Description: "Series count"},
		},
		PartitionColumns:    metricsStatusPartitionColumns(),
		PartitionProjection: metricsStatusPartitionProjection(),
	}
}

func resolveMetricsStatusTables(bucket, logicalRegion, suffix string) []ResolvedTable {
	return []ResolvedTable{
		resolveMetricsStatusTable(bucket, logicalRegion, suffix, metricsStatusSourcesSubdir, metricsStatusSourcesTableDef, metricsStatusSourcesTableName),
		resolveMetricsStatusTable(bucket, logicalRegion, suffix, metricsStatusByMetricSubdir, metricsStatusByMetricTableDef, metricsStatusByMetricTableName),
		resolveMetricsStatusTable(bucket, logicalRegion, suffix, metricsStatusByLabelSubdir, metricsStatusByLabelTableDef, metricsStatusByLabelTableName),
		resolveMetricsStatusTable(bucket, logicalRegion, suffix, metricsStatusByLabelValueSubdir, metricsStatusByLabelValueTableDef, metricsStatusByLabelValueTableName),
	}
}

const (
	metricsStatusSourcesSubdir      = "sources"
	metricsStatusByMetricSubdir     = "series_count_by_metric_name"
	metricsStatusByLabelSubdir      = "series_count_by_label_name"
	metricsStatusByLabelValueSubdir = "series_count_by_label_value_pair"
)

type metricsStatusTableDefFn func() TableDefinition
type metricsStatusTableNameFn func(string, string) string

func resolveMetricsStatusTable(
	bucket, logicalRegion, suffix, subdir string,
	defFn metricsStatusTableDefFn,
	nameFn metricsStatusTableNameFn,
) ResolvedTable {
	location := fmt.Sprintf("s3://%s/%s%s", bucket, metricsStatusDataPathSuffix, subdir)
	tableName := nameFn(logicalRegion, suffix)
	template := fmt.Sprintf("s3://%s/%s%s/biztype=${biztype}/applicationID=${applicationid}/date=${date}/",
		bucket, metricsStatusDataPathSuffix, subdir)

	def := defFn()
	def.PartitionProjection = cloneMap(def.PartitionProjection)
	def.PartitionProjection["storage.location.template"] = template

	return ResolvedTable{
		Definition:     def,
		Database:       logsDatabaseName,
		Name:           tableName,
		FullName:       logsDatabaseName + "." + tableName,
		Location:       location,
		LocationPrefix: location,
	}
}

func metricsStatusSourcesTableName(region, suffix string) string {
	return glueTableName(metricsStatusSourcesBase, region, suffix)
}

func metricsStatusByMetricTableName(region, suffix string) string {
	return glueTableName(metricsStatusByMetricBase, region, suffix)
}

func metricsStatusByLabelTableName(region, suffix string) string {
	return glueTableName(metricsStatusByLabelBase, region, suffix)
}

func metricsStatusByLabelValueTableName(region, suffix string) string {
	return glueTableName(metricsStatusByLabelValueBase, region, suffix)
}

func metricsStatusSourcesPhysicalTableName(region, suffix string) string {
	return fmt.Sprintf("%s.%s", logsDatabaseName, metricsStatusSourcesTableName(region, suffix))
}

func metricsStatusByMetricPhysicalTableName(region, suffix string) string {
	return fmt.Sprintf("%s.%s", logsDatabaseName, metricsStatusByMetricTableName(region, suffix))
}

func metricsStatusByLabelPhysicalTableName(region, suffix string) string {
	return fmt.Sprintf("%s.%s", logsDatabaseName, metricsStatusByLabelTableName(region, suffix))
}

func metricsStatusByLabelValuePhysicalTableName(region, suffix string) string {
	return fmt.Sprintf("%s.%s", logsDatabaseName, metricsStatusByLabelValueTableName(region, suffix))
}

func metricsStatusSourcesPhysicalTableSQLName(region, suffix string) string {
	return fmt.Sprintf("%s.%s", quoteIdent(logsDatabaseName), metricsStatusSourcesTableName(region, suffix))
}

func metricsStatusByMetricPhysicalTableSQLName(region, suffix string) string {
	return fmt.Sprintf("%s.%s", quoteIdent(logsDatabaseName), metricsStatusByMetricTableName(region, suffix))
}

func metricsStatusByLabelPhysicalTableSQLName(region, suffix string) string {
	return fmt.Sprintf("%s.%s", quoteIdent(logsDatabaseName), metricsStatusByLabelTableName(region, suffix))
}

func metricsStatusByLabelValuePhysicalTableSQLName(region, suffix string) string {
	return fmt.Sprintf("%s.%s", quoteIdent(logsDatabaseName), metricsStatusByLabelValueTableName(region, suffix))
}

// metricsStatusDivePath matches deltalake/global/metrics-status/*/biztype=/applicationID=/date=/
func metricsStatusDivePath() []divePathField {
	return []divePathField{
		{Name: "biztype", APIKeys: []string{"biztype", "biz_type"}, PathKey: "biztype", SQLColumn: "biztype", Projection: ProjectionInjected, Required: true},
		{Name: "applicationID", APIKeys: []string{"applicationID", "application_id", "cluster"}, PathKey: "applicationID", SQLColumn: "applicationID", Projection: ProjectionInjected, Required: true},
		{Name: "date", APIKeys: []string{"date"}, PathKey: "date", SQLColumn: "date", Projection: ProjectionInteger, Required: true, Normalize: normalizeLogStatsDate},
	}
}

func metricsStatusScopeFieldSpecs() []scopeFieldSpec {
	return []scopeFieldSpec{
		{APIKeys: []string{"biztype", "biz_type"}, SQLColumn: "biztype", Required: true},
		{APIKeys: []string{"applicationID", "application_id", "cluster"}, SQLColumn: "applicationID", Required: true},
		{APIKeys: []string{"date"}, SQLColumn: "date", Required: true, AllowLegacyDatePair: true, Normalize: normalizeLogStatsDate},
	}
}
