package executor

import (
	"fmt"
	"strings"

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

func (e *Executor) validateCreateTableExtensions(stmt *parser.CreateTableStatement) error {
	if stmt == nil {
		return nil
	}
	hasExtensions := false
	for _, col := range stmt.Columns {
		if col == nil {
			continue
		}
		if col.HasDefault || col.HasOnUpdate {
			hasExtensions = true
			break
		}
	}
	if !hasExtensions {
		return nil
	}
	if !e.extendedProtocolModeEnabled() {
		return cqlerrors.Invalid(fmt.Sprintf("column DEFAULT/ON UPDATE is only supported in executor.protocol_mode=%q", config.ExecutorProtocolModeExtendedSQL))
	}

	for _, col := range stmt.Columns {
		if col == nil {
			continue
		}
		if col.HasDefault {
			if err := validateColumnDefaultExpr(col.DefaultExpr); err != nil {
				return cqlerrors.Invalid(fmt.Sprintf("invalid DEFAULT expression for column %q: %v", col.Name, err))
			}
		}
		if col.HasOnUpdate {
			if err := validateColumnOnUpdateExpr(col.OnUpdateExpr); err != nil {
				return cqlerrors.Invalid(fmt.Sprintf("invalid ON UPDATE expression for column %q: %v", col.Name, err))
			}
		}
	}
	return nil
}

func validateColumnDefaultExpr(expr parser.Expression) error {
	if expr == nil {
		return fmt.Errorf("expression is required")
	}
	if _, ok := currentTimestampExpr(expr); ok {
		return nil
	}
	switch e := expr.(type) {
	case *parser.TypeHintExpr:
		return validateColumnDefaultExpr(e.Expr)
	case *parser.StringLiteral, *parser.BlobLiteral, *parser.IntegerLiteral,
		*parser.FloatLiteral, *parser.BooleanLiteral, *parser.UUIDLiteral, *parser.NullLiteral:
		return nil
	case *parser.UnaryExpr:
		if strings.TrimSpace(e.Op) != "+" && strings.TrimSpace(e.Op) != "-" {
			return fmt.Errorf("unsupported unary operator %q", e.Op)
		}
		return validateColumnDefaultExpr(e.Expr)
	case *parser.FunctionCall:
		if len(e.Args) > 0 {
			return fmt.Errorf("only zero-argument DEFAULT functions are supported")
		}
		if strings.EqualFold(e.Name, "now") || strings.EqualFold(e.Name, "current_timestamp") {
			return nil
		}
		return fmt.Errorf("unsupported DEFAULT function %q", e.Name)
	default:
		return fmt.Errorf("unsupported DEFAULT expression type %T", expr)
	}
}

func validateColumnOnUpdateExpr(expr parser.Expression) error {
	if expr == nil {
		return fmt.Errorf("expression is required")
	}
	if _, ok := currentTimestampExpr(expr); ok {
		return nil
	}
	return fmt.Errorf("only CURRENT_TIMESTAMP/NOW are supported")
}

func currentTimestampExpr(expr parser.Expression) (string, bool) {
	switch e := expr.(type) {
	case *parser.TypeHintExpr:
		return currentTimestampExpr(e.Expr)
	case *parser.ColumnExpr:
		if e.Table == "" && (strings.EqualFold(e.Name, "current_timestamp") || strings.EqualFold(e.Name, "now")) {
			return "CURRENT_TIMESTAMP", true
		}
	case *parser.FunctionCall:
		if len(e.Args) == 0 && (strings.EqualFold(e.Name, "current_timestamp") || strings.EqualFold(e.Name, "now")) {
			return "CURRENT_TIMESTAMP", true
		}
	}
	return "", false
}

func normalizeColumnExprForMeta(expr parser.Expression) string {
	if expr == nil {
		return ""
	}
	if ts, ok := currentTimestampExpr(expr); ok {
		return ts
	}
	return expr.String()
}
