package query

import (
	"fmt"
	"strings"
)

// Supported dataset identifiers for specialized OLAP scoping.
const (
	DatasetLogs                = "logs"
	DatasetLogStats            = "log-stats"
	DatasetLogStatsAlias       = "log_stats" // SQL virtual table name (hyphen not valid unquoted)
	DatasetTopsql              = "topsql"
	DatasetTopsqlSQLMeta       = "topsql-sql-meta"
	DatasetTopsqlSQLMetaAlias  = "topsql_sql_meta"
	DatasetTopsqlPlanMeta      = "topsql-plan-meta"
	DatasetTopsqlPlanMetaAlias = "topsql_plan_meta"
	DatasetTopru               = "topru"
	DatasetSQLStatement        = "sqlstatement"
	DatasetSlowlogs            = "slowlogs"
	DatasetRaw                 = "raw"
	// Metrics-status datasets (VM TSDB /status/tsdb snapshots under deltalake/global/metrics-status/).
	// Constants and helpers live in metrics_status.go.
)

// DatasetInfo describes a specialized virtual table exposed to callers.
type DatasetInfo struct {
	ID            string           `json:"id"`
	Alias         string           `json:"alias"`
	Description   string           `json:"description"`
	PhysicalTable string           `json:"physical_table,omitempty"`
	ScopeFields   []ScopeFieldMeta `json:"scope_fields,omitempty"` // ordered Hive dive path
	// TimeColumn / TimeFormat describe optional time_range injection (empty = not supported).
	TimeColumn string `json:"time_column,omitempty"`
	TimeFormat string `json:"time_format,omitempty"`
	// RequiresTimeRange is always false; kept for backward-compatible clients.
	RequiresTimeRange bool `json:"requires_time_range"`
}

func normalizeDataset(ds string) string {
	ds = strings.ToLower(strings.TrimSpace(ds))
	switch ds {
	case "", DatasetRaw:
		return DatasetRaw
	case DatasetLogs, "general_logs", "general-logs":
		return DatasetLogs
	case DatasetLogStats, "log_stats", "logstats":
		return DatasetLogStats
	case DatasetTopsql, "top_sql", "top-sql":
		return DatasetTopsql
	case DatasetTopsqlSQLMeta, DatasetTopsqlSQLMetaAlias, "sql_meta", "sql-meta":
		return DatasetTopsqlSQLMeta
	case DatasetTopsqlPlanMeta, DatasetTopsqlPlanMetaAlias, "plan_meta", "plan-meta":
		return DatasetTopsqlPlanMeta
	case DatasetTopru, "top_ru", "top-ru", "topsql_topru":
		return DatasetTopru
	case DatasetSQLStatement, "sql_statement", "sql-statement", "statements":
		return DatasetSQLStatement
	case DatasetSlowlogs, "slowlog", "slow_logs", "slow-logs":
		return DatasetSlowlogs
	case DatasetMetricsStatusSources, DatasetMetricsStatusSourcesAlias, "metrics_status", "metricsstatus":
		return DatasetMetricsStatusSources
	case DatasetMetricsStatusByMetric, DatasetMetricsStatusByMetricAlias:
		return DatasetMetricsStatusByMetric
	case DatasetMetricsStatusByLabel, DatasetMetricsStatusByLabelAlias:
		return DatasetMetricsStatusByLabel
	case DatasetMetricsStatusByLabelValue, DatasetMetricsStatusByLabelValueAlias:
		return DatasetMetricsStatusByLabelValue
	default:
		return ds
	}
}

func datasetVirtualAlias(ds string) string {
	switch normalizeDataset(ds) {
	case DatasetLogs:
		return DatasetLogs
	case DatasetLogStats:
		return DatasetLogStatsAlias
	case DatasetTopsql:
		return DatasetTopsql
	case DatasetTopsqlSQLMeta:
		return DatasetTopsqlSQLMetaAlias
	case DatasetTopsqlPlanMeta:
		return DatasetTopsqlPlanMetaAlias
	case DatasetTopru:
		return DatasetTopru
	case DatasetSQLStatement:
		return DatasetSQLStatement
	case DatasetSlowlogs:
		return DatasetSlowlogs
	case DatasetMetricsStatusSources:
		return DatasetMetricsStatusSourcesAlias
	case DatasetMetricsStatusByMetric:
		return DatasetMetricsStatusByMetricAlias
	case DatasetMetricsStatusByLabel:
		return DatasetMetricsStatusByLabelAlias
	case DatasetMetricsStatusByLabelValue:
		return DatasetMetricsStatusByLabelValueAlias
	default:
		return ""
	}
}

func isScopedDataset(ds string) bool {
	switch normalizeDataset(ds) {
	case DatasetLogs, DatasetLogStats, DatasetTopsql, DatasetTopsqlSQLMeta, DatasetTopsqlPlanMeta,
		DatasetTopru, DatasetSQLStatement, DatasetSlowlogs,
		DatasetMetricsStatusSources, DatasetMetricsStatusByMetric,
		DatasetMetricsStatusByLabel, DatasetMetricsStatusByLabelValue:
		return true
	default:
		return false
	}
}

func supportedDatasetsHint() string {
	return fmt.Sprintf("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s",
		DatasetLogs, DatasetLogStats, DatasetTopsql, DatasetTopsqlSQLMeta, DatasetTopsqlPlanMeta,
		DatasetTopru, DatasetSQLStatement, DatasetSlowlogs,
		DatasetMetricsStatusSources, DatasetMetricsStatusByMetric,
		DatasetMetricsStatusByLabel, DatasetMetricsStatusByLabelValue, DatasetRaw)
}

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

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

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

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

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

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

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

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

func logsPhysicalTableSQLName(region, suffix string) string {
	// Database name contains a hyphen; quote it for Athena.
	return fmt.Sprintf("%s.%s", quoteIdent(logsDatabaseName), generalLogsTableName(region, suffix))
}

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

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

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

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

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

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

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

func listDatasetInfos(cfg Config) []DatasetInfo {
	key := cfg.LogsTableRegionKey()
	suffix := cfg.LogsTableSuffix
	return []DatasetInfo{
		{
			ID:            DatasetLogs,
			Alias:         DatasetLogs,
			Description:   "Offline general logs. Query virtual table `logs`; partitions from scope; optional time_range → timestamp (unix seconds).",
			PhysicalTable: logsPhysicalTableName(key, suffix),
			ScopeFields:   scopeFieldMetas(logsDivePath()),
			TimeColumn:    "timestamp",
			TimeFormat:    TimeFormatUnixSeconds,
		},
		{
			ID:            DatasetLogStats,
			Alias:         DatasetLogStatsAlias,
			Description:   "Offline log statistics. Query virtual table `log_stats`; partitions from scope (date/org/cluster); optional time_range → hour (0-23 UTC).",
			PhysicalTable: logStatsPhysicalTableName(key, suffix),
			ScopeFields:   scopeFieldMetas(logStatsDivePath()),
			TimeColumn:    "hour",
			TimeFormat:    TimeFormatHourOfDay,
		},
		{
			ID:            DatasetTopsql,
			Alias:         DatasetTopsql,
			Description:   "TopSQL instance metrics. Query virtual table `topsql`; optional time_range → timestamps (unix seconds).",
			PhysicalTable: topsqlPhysicalTableName(key, suffix),
			ScopeFields:   scopeFieldMetas(topsqlDivePath()),
			TimeColumn:    "timestamps",
			TimeFormat:    TimeFormatUnixSeconds,
		},
		{
			ID:            DatasetTopsqlSQLMeta,
			Alias:         DatasetTopsqlSQLMetaAlias,
			Description:   "TopSQL SQL text meta. Query virtual table `topsql_sql_meta`; scope org+cluster; optional date (yyyy-MM-dd file column).",
			PhysicalTable: topsqlSQLMetaPhysicalTableName(key, suffix),
			ScopeFields:   scopeFieldMetas(topsqlSQLMetaDivePath()),
		},
		{
			ID:            DatasetTopsqlPlanMeta,
			Alias:         DatasetTopsqlPlanMetaAlias,
			Description:   "TopSQL plan text meta. Query virtual table `topsql_plan_meta`; scope org+cluster; optional date (yyyy-MM-dd file column).",
			PhysicalTable: topsqlPlanMetaPhysicalTableName(key, suffix),
			ScopeFields:   scopeFieldMetas(topsqlPlanMetaDivePath()),
		},
		{
			ID:            DatasetTopru,
			Alias:         DatasetTopru,
			Description:   "TopRU metrics (component=topru/instance=default). Query virtual table `topru`; optional time_range → timestamps.",
			PhysicalTable: topruPhysicalTableName(key, suffix),
			ScopeFields:   scopeFieldMetas(topruDivePath()),
			TimeColumn:    "timestamps",
			TimeFormat:    TimeFormatUnixSeconds,
		},
		{
			ID:            DatasetSQLStatement,
			Alias:         DatasetSQLStatement,
			Description:   "SQL statement summaries. Query virtual table `sqlstatement`; optional time_range → overlapping begin/end windows.",
			PhysicalTable: sqlstatementPhysicalTableName(key, suffix),
			ScopeFields:   scopeFieldMetas(sqlstatementDivePath()),
			TimeColumn:    "begin,end",
			TimeFormat:    TimeFormatWindowOverlap,
		},
		{
			ID:            DatasetSlowlogs,
			Alias:         DatasetSlowlogs,
			Description:   "Slow query logs (legacy Delta deltalake/{org}/{cluster}/slowlogs/date=yyyyMMdd/). Query virtual table `slowlogs`; scope org+cluster+date; optional time_range → time.",
			PhysicalTable: slowlogsPhysicalTableName(key, suffix),
			ScopeFields:   scopeFieldMetas(slowlogsDivePath()),
			TimeColumn:    "time",
			TimeFormat:    TimeFormatUnixFloat,
		},
		{
			ID:            DatasetMetricsStatusSources,
			Alias:         DatasetMetricsStatusSourcesAlias,
			Description:   "VM TSDB status summary per cluster/day. Query virtual table `metrics_status_sources`; scope biztype+applicationID+date.",
			PhysicalTable: metricsStatusSourcesPhysicalTableName(key, suffix),
			ScopeFields:   scopeFieldMetas(metricsStatusDivePath()),
		},
		{
			ID:            DatasetMetricsStatusByMetric,
			Alias:         DatasetMetricsStatusByMetricAlias,
			Description:   "VM TSDB series count by metric name. Query virtual table `metrics_status_by_metric_name`; scope biztype+applicationID+date.",
			PhysicalTable: metricsStatusByMetricPhysicalTableName(key, suffix),
			ScopeFields:   scopeFieldMetas(metricsStatusDivePath()),
		},
		{
			ID:            DatasetMetricsStatusByLabel,
			Alias:         DatasetMetricsStatusByLabelAlias,
			Description:   "VM TSDB series count by label name. Query virtual table `metrics_status_by_label_name`; scope biztype+applicationID+date.",
			PhysicalTable: metricsStatusByLabelPhysicalTableName(key, suffix),
			ScopeFields:   scopeFieldMetas(metricsStatusDivePath()),
		},
		{
			ID:            DatasetMetricsStatusByLabelValue,
			Alias:         DatasetMetricsStatusByLabelValueAlias,
			Description:   "VM TSDB series count by label value pair. Query virtual table `metrics_status_by_label_value_pair`; scope biztype+applicationID+date.",
			PhysicalTable: metricsStatusByLabelValuePhysicalTableName(key, suffix),
			ScopeFields:   scopeFieldMetas(metricsStatusDivePath()),
		},
		{
			ID:          DatasetRaw,
			Alias:       "",
			Description: "Raw Athena SQL against any catalog table. Do not pass scope/time_range.",
		},
	}
}
