package translator

import (
	"fmt"
	"strings"

	"github.com/everything-on-mysql/cassandra-on-mysql/pkg/cql/parser"
)

const (
	// TTLRawOptionName is the canonical CQL table option key used to pass TTL clause fragments.
	TTLRawOptionName = "ttl"
)

const removedTTLRawOptionName = "tidb_ttl_raw"

// TTLRawClauseFromOptions extracts and validates the raw TTL clause fragment.
// Example value:
//
//	"TTL = `created_at` + INTERVAL 30 DAY TTL_ENABLE='ON' TTL_JOB_INTERVAL='24h'"
//
// For ALTER TABLE, allowRemove=true also allows "REMOVE TTL".
func TTLRawClauseFromOptions(options map[string]interface{}, allowRemove bool) (string, bool, error) {
	if len(options) == 0 {
		return "", false, nil
	}

	var rawValue interface{}
	hasRaw := false
	for key, value := range options {
		normalized := normalizeTableOptionKey(key)
		if strings.EqualFold(normalized, removedTTLRawOptionName) {
			return "", true, fmt.Errorf("%s is removed, use %s instead", removedTTLRawOptionName, TTLRawOptionName)
		}
		if strings.EqualFold(normalized, TTLRawOptionName) {
			if hasRaw {
				return "", true, fmt.Errorf("%s is duplicated", TTLRawOptionName)
			}
			rawValue = value
			hasRaw = true
		}
	}
	if !hasRaw {
		return "", false, nil
	}

	raw, err := tableOptionStringLiteral(rawValue)
	if err != nil {
		return "", true, fmt.Errorf("invalid %s: %w", TTLRawOptionName, err)
	}
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return "", true, fmt.Errorf("%s cannot be empty", TTLRawOptionName)
	}
	if strings.ContainsAny(raw, "\r\n\t") {
		return "", true, fmt.Errorf("%s cannot contain control whitespace", TTLRawOptionName)
	}
	if strings.Contains(raw, ";") || strings.Contains(raw, "--") || strings.Contains(raw, "/*") || strings.Contains(raw, "*/") || strings.Contains(raw, "#") {
		return "", true, fmt.Errorf("%s contains forbidden SQL token", TTLRawOptionName)
	}

	upperRaw := strings.ToUpper(raw)
	if allowRemove && upperRaw == "REMOVE TTL" {
		return raw, true, nil
	}
	if strings.HasPrefix(upperRaw, "TTL ") || strings.HasPrefix(upperRaw, "TTL=") {
		return raw, true, nil
	}
	if allowRemove {
		if strings.HasPrefix(upperRaw, "TTL_ENABLE ") || strings.HasPrefix(upperRaw, "TTL_ENABLE=") {
			return raw, true, nil
		}
		if strings.HasPrefix(upperRaw, "TTL_JOB_INTERVAL ") || strings.HasPrefix(upperRaw, "TTL_JOB_INTERVAL=") {
			return raw, true, nil
		}
	}
	return "", true, fmt.Errorf("%s must start with TTL = ...%s", TTLRawOptionName, ternaryAllowRemove(allowRemove, ", TTL_ENABLE = ..., TTL_JOB_INTERVAL = ..., or be REMOVE TTL", ""))
}

func normalizeTableOptionKey(key string) string {
	trimmed := strings.TrimSpace(key)
	if len(trimmed) >= 2 && trimmed[0] == '\'' && trimmed[len(trimmed)-1] == '\'' {
		return trimmed[1 : len(trimmed)-1]
	}
	return trimmed
}

func tableOptionStringLiteral(value interface{}) (string, error) {
	switch v := value.(type) {
	case parser.Expression:
		switch e := v.(type) {
		case *parser.TypeHintExpr:
			return tableOptionStringLiteral(e.Expr)
		case *parser.StringLiteral:
			return e.Value, nil
		default:
			return "", fmt.Errorf("value must be a string literal")
		}
	case string:
		return v, nil
	default:
		return "", fmt.Errorf("value type %T is not supported", value)
	}
}

func ternaryAllowRemove(allow bool, whenTrue, whenFalse string) string {
	if allow {
		return whenTrue
	}
	return whenFalse
}
