package query

import (
	"fmt"
	"os"
	"regexp"
	"strconv"
	"strings"
)

const (
	defaultAthenaWorkGroupPrefix   = "o11y-olap"
	athenaWorkGroupProjectTagKey   = "project"
	athenaWorkGroupProjectTagValue = "o11y-olap"
	// AthenaResultsPathSuffix is the object prefix for Athena query results in the shared bucket.
	AthenaResultsPathSuffix = "athena-results/logs-query/"

	envOlapDefaultWaitSeconds = "OLAP_DEFAULT_WAIT_SECONDS"
	envOlapMaxWaitSeconds     = "OLAP_MAX_WAIT_SECONDS"

	fallbackDefaultWaitSeconds = 30
	fallbackMaxWaitSeconds     = 60
)

// o11y-{env}-shared-{logical_region}, e.g. o11y-prod-shared-us-east-1-serverless
var sharedBucketLogicalRegionRe = regexp.MustCompile(`(?i)^o11y-(?:prod|dev|staging)-shared-(.+)$`)

// Config configures the diagnosis-query SQL analytics layer.
type Config struct {
	Vendor string
	Region string // physical cloud region (AWS/GCP/...), used for SDK clients

	// Logs OLAP catalog (AWS Glue)
	LogsBucket      string // S3 bucket hosting deltalake/global/logs/
	LogsTableSuffix string // optional extra table suffix, e.g. staging

	// Athena (AWS only)
	AthenaWorkGroup      string
	AthenaDatabase       string
	AthenaCatalog        string
	AthenaOutputLocation string // s3://bucket/athena-results/logs-query/

	// OLAP submit wait (POST /olap). Overridable via OLAP_DEFAULT_WAIT_SECONDS /
	// OLAP_MAX_WAIT_SECONDS. Request wait_seconds=0 stays async.
	DefaultWaitSeconds int
	MaxWaitSeconds     int
}

// DefaultConfigFromEnv builds config with sensible defaults for a region.
// AthenaOutputLocation and AthenaWorkGroup are filled from BUCKET_NAME via ApplyLogsSettings.
func DefaultConfigFromEnv(vendor, region string) Config {
	cfg := Config{
		Vendor:        vendor,
		Region:        region,
		AthenaCatalog: "AwsDataCatalog",
		// Same Glue DB as registry tables (logsDatabaseName). Raw SQL without a
		// schema qualifier resolves here. Legacy org tables in Glue "default"
		// must pass request database=default.
		AthenaDatabase: "o11y-logs",
	}
	if region == "" {
		cfg.Region = "us-west-2"
	}
	cfg.DefaultWaitSeconds = envIntOr(envOlapDefaultWaitSeconds, fallbackDefaultWaitSeconds)
	cfg.MaxWaitSeconds = envIntOr(envOlapMaxWaitSeconds, fallbackMaxWaitSeconds)
	cfg.normalizeWaitSeconds()
	return cfg
}

func (c *Config) normalizeWaitSeconds() {
	if c.MaxWaitSeconds <= 0 {
		c.MaxWaitSeconds = fallbackMaxWaitSeconds
	}
	if c.DefaultWaitSeconds <= 0 {
		c.DefaultWaitSeconds = fallbackDefaultWaitSeconds
	}
	if c.DefaultWaitSeconds > c.MaxWaitSeconds {
		c.DefaultWaitSeconds = c.MaxWaitSeconds
	}
}

func envIntOr(key string, fallback int) int {
	raw := strings.TrimSpace(os.Getenv(key))
	if raw == "" {
		return fallback
	}
	n, err := strconv.Atoi(raw)
	if err != nil || n < 0 {
		return fallback
	}
	return n
}

// ApplyOverrides fills Athena settings when non-empty.
func (c *Config) ApplyOverrides(workgroup, database, catalog, output string) {
	if workgroup != "" {
		c.AthenaWorkGroup = workgroup
	}
	if database != "" {
		c.AthenaDatabase = database
	}
	if catalog != "" {
		c.AthenaCatalog = catalog
	}
	if output != "" {
		c.AthenaOutputLocation = normalizeS3URI(output)
	}
}

// ApplyLogsSettings fills logs catalog bucket / table suffix when non-empty.
// When AthenaOutputLocation is unset, derives s3://{bucket}/athena-results/logs-query/.
// When AthenaWorkGroup is unset, derives o11y-olap-{logical_region} from the bucket.
func (c *Config) ApplyLogsSettings(bucket, tableSuffix string) {
	if bucket != "" {
		c.LogsBucket = strings.TrimSpace(bucket)
	}
	if tableSuffix != "" {
		c.LogsTableSuffix = tableSuffix
	}
	if c.AthenaOutputLocation == "" && c.LogsBucket != "" {
		c.AthenaOutputLocation = defaultAthenaOutputLocation(c.LogsBucket)
	}
	if c.AthenaWorkGroup == "" {
		c.AthenaWorkGroup = defaultAthenaWorkGroupName(c.LogsTableRegionKey())
	}
}

// ResolvedAthenaWorkGroup returns the configured workgroup or derives one from bucket/region.
func (c Config) ResolvedAthenaWorkGroup() string {
	if wg := strings.TrimSpace(c.AthenaWorkGroup); wg != "" {
		return wg
	}
	return defaultAthenaWorkGroupName(c.LogsTableRegionKey())
}

func defaultAthenaWorkGroupName(logicalRegion string) string {
	logicalRegion = strings.TrimSpace(logicalRegion)
	if logicalRegion == "" {
		return defaultAthenaWorkGroupPrefix
	}
	return defaultAthenaWorkGroupPrefix + "-" + logicalRegion
}

// LogsTableRegionKey is the logical region used in Glue table names.
// Prefer the suffix of BUCKET_NAME (o11y-{env}-shared-{logical}); fall back to physical Region.
func (c Config) LogsTableRegionKey() string {
	if lr := logicalRegionFromBucket(c.LogsBucket); lr != "" {
		return lr
	}
	return strings.TrimSpace(c.Region)
}

// logicalRegionFromBucket extracts logical region from
// o11y-{prod|dev|staging}-shared-{logical_region}.
func logicalRegionFromBucket(bucket string) string {
	bucket = strings.TrimSpace(bucket)
	bucket = strings.TrimPrefix(bucket, "s3://")
	bucket = strings.Trim(bucket, "/")
	m := sharedBucketLogicalRegionRe.FindStringSubmatch(bucket)
	if len(m) != 2 {
		return ""
	}
	return m[1]
}

func defaultAthenaOutputLocation(bucket string) string {
	bucket = strings.TrimSpace(bucket)
	bucket = strings.TrimPrefix(bucket, "s3://")
	bucket = strings.Trim(bucket, "/")
	if bucket == "" {
		return ""
	}
	return fmt.Sprintf("s3://%s/%s", bucket, AthenaResultsPathSuffix)
}

func normalizeS3URI(uri string) string {
	uri = strings.TrimSpace(uri)
	if uri == "" {
		return ""
	}
	if !strings.HasPrefix(uri, "s3://") {
		uri = "s3://" + strings.TrimPrefix(uri, "/")
	}
	if !strings.HasSuffix(uri, "/") {
		uri += "/"
	}
	return uri
}

func normalizeProvider(p string) string {
	return strings.ToLower(strings.TrimSpace(p))
}
