package telemetrylogs

import (
	"context"
	"testing"
	"time"

	"github.com/SigNoz/signoz/pkg/flagger/flaggertest"
	qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
	"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
	"github.com/huandu/go-sqlbuilder"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestExistsConditionForWithEvolutions(t *testing.T) {
	testCases := []struct {
		name          string
		startTs       uint64
		endTs         uint64
		key           telemetrytypes.TelemetryFieldKey
		operator      qbtypes.FilterOperator
		value         any
		expectedSQL   string
		expectedArgs  []any
		expectedError error
	}{
		{
			name:    "New column",
			startTs: uint64(time.Date(2024, 1, 15, 10, 0, 0, 0, time.UTC).UnixNano()),
			endTs:   uint64(time.Date(2024, 1, 15, 10, 0, 0, 0, time.UTC).UnixNano()),
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "service.name",
				FieldContext:  telemetrytypes.FieldContextResource,
				FieldDataType: telemetrytypes.FieldDataTypeString,
				Evolutions: []*telemetrytypes.EvolutionEntry{
					{
						Signal:       telemetrytypes.SignalLogs,
						ColumnName:   "resources_string",
						FieldContext: telemetrytypes.FieldContextResource,
						ColumnType:   "Map(LowCardinality(String), String)",
						FieldName:    "__all__",
						ReleaseTime:  time.Unix(0, 0),
					},
					{
						Signal:       telemetrytypes.SignalLogs,
						ColumnName:   "resource",
						ColumnType:   "JSON()",
						FieldContext: telemetrytypes.FieldContextResource,
						FieldName:    "__all__",
						ReleaseTime:  time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
					},
				},
			},
			operator:      qbtypes.FilterOperatorExists,
			value:         nil,
			expectedSQL:   "WHERE resource.`service.name`::String IS NOT NULL",
			expectedError: nil,
		},
		{
			name:    "Old column",
			startTs: uint64(time.Date(2023, 1, 15, 10, 0, 0, 0, time.UTC).UnixNano()),
			endTs:   uint64(time.Date(2023, 1, 15, 10, 0, 0, 0, time.UTC).UnixNano()),
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "service.name",
				FieldContext:  telemetrytypes.FieldContextResource,
				FieldDataType: telemetrytypes.FieldDataTypeString,
				Evolutions: []*telemetrytypes.EvolutionEntry{
					{
						Signal:       telemetrytypes.SignalLogs,
						ColumnName:   "resources_string",
						FieldContext: telemetrytypes.FieldContextResource,
						ColumnType:   "Map(LowCardinality(String), String)",
						FieldName:    "__all__",
						ReleaseTime:  time.Unix(0, 0),
					},
					{
						Signal:       telemetrytypes.SignalLogs,
						ColumnName:   "resource",
						ColumnType:   "JSON()",
						FieldContext: telemetrytypes.FieldContextResource,
						FieldName:    "__all__",
						ReleaseTime:  time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
					},
				},
			},
			operator:      qbtypes.FilterOperatorExists,
			value:         nil,
			expectedSQL:   "WHERE mapContains(resources_string, 'service.name') = ?",
			expectedArgs:  []any{true},
			expectedError: nil,
		},
		{
			name:    "Both Old column and new - empty filter",
			startTs: uint64(time.Date(2023, 1, 15, 10, 0, 0, 0, time.UTC).UnixNano()),
			endTs:   uint64(time.Date(2024, 1, 15, 10, 0, 0, 0, time.UTC).UnixNano()),
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "service.name",
				FieldContext:  telemetrytypes.FieldContextResource,
				FieldDataType: telemetrytypes.FieldDataTypeString,
				Evolutions: []*telemetrytypes.EvolutionEntry{
					{
						Signal:       telemetrytypes.SignalLogs,
						ColumnName:   "resources_string",
						FieldContext: telemetrytypes.FieldContextResource,
						ColumnType:   "Map(LowCardinality(String), String)",
						FieldName:    "__all__",
						ReleaseTime:  time.Unix(0, 0),
					},
					{
						Signal:       telemetrytypes.SignalLogs,
						ColumnName:   "resource",
						ColumnType:   "JSON()",
						FieldContext: telemetrytypes.FieldContextResource,
						FieldName:    "__all__",
						ReleaseTime:  time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
					},
				},
			},
			operator:      qbtypes.FilterOperatorExists,
			value:         nil,
			expectedSQL:   "WHERE multiIf(resource.`service.name` IS NOT NULL, resource.`service.name`::String, mapContains(resources_string, 'service.name'), resources_string['service.name'], NULL) IS NOT NULL",
			expectedError: nil,
		},
	}
	fl := flaggertest.New(t)
	fm := NewFieldMapper(fl)
	conditionBuilder := NewConditionBuilder(fm, fl)
	ctx := context.Background()

	for _, tc := range testCases {
		sb := sqlbuilder.NewSelectBuilder()
		t.Run(tc.name, func(t *testing.T) {
			cond, err := conditionBuilder.ConditionFor(ctx, tc.startTs, tc.endTs, &tc.key, tc.operator, tc.value, sb)
			sb.Where(cond)

			if tc.expectedError != nil {
				assert.Equal(t, tc.expectedError, err)
			} else {
				require.NoError(t, err)
				sql, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
				assert.Contains(t, sql, tc.expectedSQL)
				assert.Equal(t, tc.expectedArgs, args)
			}
		})
	}
}

func TestConditionFor(t *testing.T) {
	ctx := context.Background()

	mockEvolution := mockEvolutionData(time.Date(2024, 2, 1, 0, 0, 0, 0, time.UTC))
	testCases := []struct {
		name          string
		key           telemetrytypes.TelemetryFieldKey
		operator      qbtypes.FilterOperator
		value         any
		evolutions    []*telemetrytypes.EvolutionEntry
		expectedSQL   string
		expectedArgs  []any
		expectedError error
	}{
		{
			name: "Equal operator - string",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "body",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorEqual,
			value:         "error message",
			expectedSQL:   "body = ?",
			expectedArgs:  []any{"error message"},
			expectedError: nil,
		},
		{
			name: "Greater Than operator - number attribute",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "request.duration",
				FieldContext:  telemetrytypes.FieldContextAttribute,
				FieldDataType: telemetrytypes.FieldDataTypeNumber,
			},
			operator:      qbtypes.FilterOperatorGreaterThan,
			value:         float64(100),
			expectedSQL:   "(toFloat64(attributes_number['request.duration']) > ? AND mapContains(attributes_number, 'request.duration') = ?)",
			expectedArgs:  []any{float64(100), true},
			expectedError: nil,
		},
		{
			name: "Less Than operator - number attribute",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "request.size",
				FieldContext:  telemetrytypes.FieldContextAttribute,
				FieldDataType: telemetrytypes.FieldDataTypeNumber,
			},
			operator:      qbtypes.FilterOperatorLessThan,
			value:         float64(1024),
			expectedSQL:   "(toFloat64(attributes_number['request.size']) < ? AND mapContains(attributes_number, 'request.size') = ?)",
			expectedArgs:  []any{float64(1024), true},
			expectedError: nil,
		},
		{
			name: "Like operator - body",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "body",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorLike,
			value:         "%error%",
			expectedSQL:   "LOWER(body) LIKE LOWER(?)",
			expectedArgs:  []any{"%error%"},
			expectedError: nil,
		},
		{
			name: "Not Like operator - body",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "body",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorNotLike,
			value:         "%error%",
			expectedSQL:   "LOWER(body) NOT LIKE LOWER(?)",
			expectedArgs:  []any{"%error%"},
			expectedError: nil,
		},
		{
			name: "ILike operator - string attribute",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "user.id",
				FieldContext:  telemetrytypes.FieldContextAttribute,
				FieldDataType: telemetrytypes.FieldDataTypeString,
			},
			operator:      qbtypes.FilterOperatorILike,
			value:         "%admin%",
			expectedSQL:   "(LOWER(attributes_string['user.id']) LIKE LOWER(?) AND mapContains(attributes_string, 'user.id') = ?)",
			expectedArgs:  []any{"%admin%", true},
			expectedError: nil,
		},
		{
			name: "Not ILike operator - string attribute",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "user.id",
				FieldContext:  telemetrytypes.FieldContextAttribute,
				FieldDataType: telemetrytypes.FieldDataTypeString,
			},
			operator:      qbtypes.FilterOperatorNotILike,
			value:         "%admin%",
			expectedSQL:   "WHERE LOWER(attributes_string['user.id']) NOT LIKE LOWER(?)",
			expectedArgs:  []any{"%admin%"},
			expectedError: nil,
		},
		{
			name: "Contains operator - string attribute number value",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "user.id",
				FieldContext:  telemetrytypes.FieldContextAttribute,
				FieldDataType: telemetrytypes.FieldDataTypeString,
			},
			operator:      qbtypes.FilterOperatorContains,
			value:         521509198310,
			expectedSQL:   "LOWER(attributes_string['user.id']) LIKE LOWER(?)",
			expectedArgs:  []any{"%521509198310%", true},
			expectedError: nil,
		},
		{
			name: "Contains operator - body",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "body",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorContains,
			value:         521509198310,
			expectedSQL:   "LOWER(body) LIKE LOWER(?)",
			expectedArgs:  []any{"%521509198310%"},
			expectedError: nil,
		},
		{
			name: "Contains operator - string attribute",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "user.id",
				FieldContext:  telemetrytypes.FieldContextAttribute,
				FieldDataType: telemetrytypes.FieldDataTypeString,
			},
			operator:      qbtypes.FilterOperatorContains,
			value:         "admin",
			expectedSQL:   "(LOWER(attributes_string['user.id']) LIKE LOWER(?) AND mapContains(attributes_string, 'user.id') = ?)",
			expectedArgs:  []any{"%admin%", true},
			expectedError: nil,
		},
		{
			name: "In operator - severity_text",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "severity_text",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorIn,
			value:         []any{"error", "fatal", "critical"},
			expectedSQL:   "(severity_text = ? OR severity_text = ? OR severity_text = ?)",
			expectedArgs:  []any{"error", "fatal", "critical"},
			expectedError: nil,
		},
		{
			name: "In operator - invalid value",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "severity_text",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorIn,
			value:         "error",
			expectedSQL:   "",
			expectedError: qbtypes.ErrInValues,
		},
		{
			name: "Not In operator - severity_text",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "severity_text",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorNotIn,
			value:         []any{"debug", "info", "trace"},
			expectedSQL:   "(severity_text <> ? AND severity_text <> ? AND severity_text <> ?)",
			expectedArgs:  []any{"debug", "info", "trace"},
			expectedError: nil,
		},
		{
			name: "Exists operator - string field",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "body",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorExists,
			value:         nil,
			expectedSQL:   "WHERE body <> ?",
			expectedArgs:  []any{""},
			expectedError: nil,
		},
		{
			name: "Not Exists operator - string field",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "body",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorNotExists,
			value:         nil,
			expectedSQL:   "WHERE body = ?",
			expectedArgs:  []any{""},
			expectedError: nil,
		},
		{
			name: "Exists operator - map field",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "user.id",
				FieldContext:  telemetrytypes.FieldContextAttribute,
				FieldDataType: telemetrytypes.FieldDataTypeString,
			},
			operator:      qbtypes.FilterOperatorExists,
			value:         nil,
			expectedSQL:   "mapContains(attributes_string, 'user.id') = ?",
			expectedArgs:  []any{true},
			expectedError: nil,
		},
		{
			name: "Not Exists operator - map field",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "user.id",
				FieldContext:  telemetrytypes.FieldContextAttribute,
				FieldDataType: telemetrytypes.FieldDataTypeString,
			},
			operator:      qbtypes.FilterOperatorNotExists,
			value:         nil,
			expectedSQL:   "mapContains(attributes_string, 'user.id') <> ?",
			expectedArgs:  []any{true},
			expectedError: nil,
		},
		{
			name: "Exists operator - json field",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "service.name",
				FieldContext:  telemetrytypes.FieldContextResource,
				FieldDataType: telemetrytypes.FieldDataTypeString,
			},
			evolutions:    mockEvolution,
			operator:      qbtypes.FilterOperatorExists,
			value:         nil,
			expectedSQL:   "mapContains(resources_string, 'service.name') = ?",
			expectedArgs:  []any{true},
			expectedError: nil,
		},
		{
			name: "Not Exists operator - json field",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "service.name",
				FieldContext:  telemetrytypes.FieldContextResource,
				FieldDataType: telemetrytypes.FieldDataTypeString,
			},
			evolutions:    mockEvolution,
			operator:      qbtypes.FilterOperatorNotExists,
			value:         nil,
			expectedSQL:   "mapContains(resources_string, 'service.name') <> ?",
			expectedArgs:  []any{true},
			expectedError: nil,
		},
		{
			name: "Regexp operator - body field",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "body",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorRegexp,
			value:         "error.*failed",
			expectedSQL:   "match(LOWER(body), LOWER(?))",
			expectedArgs:  []any{"error.*failed"},
			expectedError: nil,
		},
		{
			name: "Not Regexp operator - body field",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "body",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorNotRegexp,
			value:         "debug|trace",
			expectedSQL:   "NOT match(LOWER(body), LOWER(?))",
			expectedArgs:  []any{"debug|trace"},
			expectedError: nil,
		},
		{
			name: "Regexp operator - string attribute",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "http.url",
				FieldContext:  telemetrytypes.FieldContextAttribute,
				FieldDataType: telemetrytypes.FieldDataTypeString,
			},
			operator:      qbtypes.FilterOperatorRegexp,
			value:         "^https://.*\\.example\\.com.*$",
			expectedSQL:   "(match(attributes_string['http.url'], ?) AND mapContains(attributes_string, 'http.url') = ?)",
			expectedArgs:  []any{"^https://.*\\.example\\.com.*$", true},
			expectedError: nil,
		},
		{
			name: "Not Regexp operator - string attribute",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "http.url",
				FieldContext:  telemetrytypes.FieldContextAttribute,
				FieldDataType: telemetrytypes.FieldDataTypeString,
			},
			operator:      qbtypes.FilterOperatorNotRegexp,
			value:         "^http://localhost.*",
			expectedSQL:   "WHERE NOT match(attributes_string['http.url'], ?)",
			expectedArgs:  []any{"^http://localhost.*"},
			expectedError: nil,
		},
		{
			name: "Regexp operator - resource attribute",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "service.name",
				FieldContext:  telemetrytypes.FieldContextResource,
				FieldDataType: telemetrytypes.FieldDataTypeString,
				Materialized:  true,
			},
			evolutions:    mockEvolution,
			operator:      qbtypes.FilterOperatorRegexp,
			value:         "frontend-.*",
			expectedSQL:   "WHERE (match(`resource_string_service$$name`, ?) AND `resource_string_service$$name_exists` = ?)",
			expectedArgs:  []any{"frontend-.*", true},
			expectedError: nil,
		},
		{
			name: "Not Regexp operator - resource attribute",
			key: telemetrytypes.TelemetryFieldKey{
				Name:          "service.name",
				FieldContext:  telemetrytypes.FieldContextResource,
				FieldDataType: telemetrytypes.FieldDataTypeString,
				Materialized:  true,
			},
			evolutions:    mockEvolution,
			operator:      qbtypes.FilterOperatorNotRegexp,
			value:         "test-.*",
			expectedSQL:   "WHERE NOT match(`resource_string_service$$name`, ?)",
			expectedArgs:  []any{"test-.*"},
			expectedError: nil,
		},
		{
			name: "Regexp operator - severity_text",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "severity_text",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorRegexp,
			value:         "ERROR|FATAL|CRITICAL",
			expectedSQL:   "match(severity_text, ?)",
			expectedArgs:  []any{"ERROR|FATAL|CRITICAL"},
			expectedError: nil,
		},
		{
			name: "Not Regexp operator - severity_text",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "severity_text",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorNotRegexp,
			value:         "DEBUG|TRACE",
			expectedSQL:   "NOT match(severity_text, ?)",
			expectedArgs:  []any{"DEBUG|TRACE"},
			expectedError: nil,
		},
		{
			name: "Non-existent column",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "nonexistent_field",
				FieldContext: telemetrytypes.FieldContextLog,
			},
			operator:      qbtypes.FilterOperatorEqual,
			value:         "value",
			expectedSQL:   "",
			expectedError: qbtypes.ErrColumnNotFound,
		},
	}
	fl := flaggertest.New(t)
	fm := NewFieldMapper(fl)
	conditionBuilder := NewConditionBuilder(fm, fl)
	for _, tc := range testCases {
		sb := sqlbuilder.NewSelectBuilder()
		t.Run(tc.name, func(t *testing.T) {
			tc.key.Evolutions = tc.evolutions
			cond, err := conditionBuilder.ConditionFor(ctx, 0, 0, &tc.key, tc.operator, tc.value, sb)
			sb.Where(cond)

			if tc.expectedError != nil {
				assert.Equal(t, tc.expectedError, err)
			} else {
				require.NoError(t, err)
				sql, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
				assert.Contains(t, sql, tc.expectedSQL)
				assert.Equal(t, tc.expectedArgs, args)
			}
		})
	}
}

func TestConditionForMultipleKeys(t *testing.T) {
	ctx := context.Background()

	testCases := []struct {
		name          string
		keys          []telemetrytypes.TelemetryFieldKey
		operator      qbtypes.FilterOperator
		value         any
		expectedSQL   string
		expectedArgs  []any
		expectedError error
	}{
		{
			name: "Equal operator - string",
			keys: []telemetrytypes.TelemetryFieldKey{
				{
					Name:         "body",
					FieldContext: telemetrytypes.FieldContextLog,
				},
				{
					Name:         "severity_text",
					FieldContext: telemetrytypes.FieldContextLog,
				},
			},
			operator:      qbtypes.FilterOperatorEqual,
			value:         "error message",
			expectedSQL:   "body = ? AND severity_text = ?",
			expectedArgs:  []any{"error message", "error message"},
			expectedError: nil,
		},
	}

	fl := flaggertest.New(t)
	fm := NewFieldMapper(fl)
	conditionBuilder := NewConditionBuilder(fm, fl)

	for _, tc := range testCases {
		sb := sqlbuilder.NewSelectBuilder()
		t.Run(tc.name, func(t *testing.T) {
			var err error
			for _, key := range tc.keys {
				cond, err := conditionBuilder.conditionFor(ctx, 0, 0, &key, tc.operator, tc.value, sb)
				sb.Where(cond)
				if err != nil {
					t.Fatalf("Error getting condition for key %s: %v", key.Name, err)
				}
			}

			if tc.expectedError != nil {
				assert.Equal(t, tc.expectedError, err)
			} else {
				require.NoError(t, err)
				sql, _ := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
				assert.Contains(t, sql, tc.expectedSQL)
			}
		})
	}
}

func TestConditionForJSONBodySearch(t *testing.T) {
	ctx := context.Background()

	testCases := []struct {
		name          string
		key           telemetrytypes.TelemetryFieldKey
		operator      qbtypes.FilterOperator
		value         any
		expectedSQL   string
		expectedError error
	}{
		{
			name: "Equal operator - int64",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.status_code",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorEqual,
			value:         200,
			expectedSQL:   `JSONExtract(JSON_VALUE(body, '$."http"."status_code"'), 'Int64') = ?`,
			expectedError: nil,
		},
		{
			name: "Equal operator - float64",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "duration_ms",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorEqual,
			value:         405.5,
			expectedSQL:   `JSONExtract(JSON_VALUE(body, '$."duration_ms"'), 'Float64') = ?`,
			expectedError: nil,
		},
		{
			name: "Equal operator - string",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.method",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorEqual,
			value:         "GET",
			expectedSQL:   `JSON_VALUE(body, '$."http"."method"') = ?`,
			expectedError: nil,
		},
		{
			name: "Equal operator - bool",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.success",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorEqual,
			value:         true,
			expectedSQL:   `JSONExtract(JSON_VALUE(body, '$."http"."success"'), 'Bool') = ?`,
			expectedError: nil,
		},
		{
			name: "Exists operator",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.status_code",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorExists,
			value:         nil,
			expectedSQL:   `JSON_EXISTS(body, '$."http"."status_code"')`,
			expectedError: nil,
		},
		{
			name: "Not Exists operator",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.status_code",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorNotExists,
			value:         nil,
			expectedSQL:   `NOT JSON_EXISTS(body, '$."http"."status_code"')`,
			expectedError: nil,
		},
		{
			name: "Greater than operator - string",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.status_code",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorGreaterThan,
			value:         "200",
			expectedSQL:   `JSONExtract(JSON_VALUE(body, '$."http"."status_code"'), 'Int64') > ?`,
			expectedError: nil,
		},
		{
			name: "Greater than operator - int64",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.status_code",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorGreaterThan,
			value:         200,
			expectedSQL:   `JSONExtract(JSON_VALUE(body, '$."http"."status_code"'), 'Int64') > ?`,
			expectedError: nil,
		},
		{
			name: "Less than operator - string",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.status_code",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorLessThan,
			value:         "300",
			expectedSQL:   `JSONExtract(JSON_VALUE(body, '$."http"."status_code"'), 'Int64') < ?`,
			expectedError: nil,
		},
		{
			name: "Less than operator - int64",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.status_code",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorLessThan,
			value:         300,
			expectedSQL:   `JSONExtract(JSON_VALUE(body, '$."http"."status_code"'), 'Int64') < ?`,
			expectedError: nil,
		},
		{
			name: "Contains operator - string",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.status_code",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorContains,
			value:         "200",
			expectedSQL:   `LOWER(JSON_VALUE(body, '$."http"."status_code"')) LIKE LOWER(?)`,
			expectedError: nil,
		},
		{
			name: "Not Contains operator - string",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.status_code",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorNotContains,
			value:         "200",
			expectedSQL:   `LOWER(JSON_VALUE(body, '$."http"."status_code"')) NOT LIKE LOWER(?)`,
			expectedError: nil,
		},
		{
			name: "Between operator - string",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.status_code",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorBetween,
			value:         []any{"200", "300"},
			expectedSQL:   `JSONExtract(JSON_VALUE(body, '$."http"."status_code"'), 'Int64') BETWEEN ? AND ?`,
			expectedError: nil,
		},
		{
			name: "Between operator - int64",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.status_code",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorBetween,
			value:         []any{400, 500},
			expectedSQL:   `JSONExtract(JSON_VALUE(body, '$."http"."status_code"'), 'Int64') BETWEEN ? AND ?`,
			expectedError: nil,
		},
		{
			name: "In operator - string",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.status_code",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorIn,
			value:         []any{"200", "300"},
			expectedSQL:   `(JSONExtract(JSON_VALUE(body, '$."http"."status_code"'), 'Int64') = ? OR JSONExtract(JSON_VALUE(body, '$."http"."status_code"'), 'Int64') = ?)`,
			expectedError: nil,
		},
		{
			name: "In operator - int64",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.status_code",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorIn,
			value:         []any{401, 404, 500},
			expectedSQL:   `(JSONExtract(JSON_VALUE(body, '$."http"."status_code"'), 'Int64') = ? OR JSONExtract(JSON_VALUE(body, '$."http"."status_code"'), 'Int64') = ? OR JSONExtract(JSON_VALUE(body, '$."http"."status_code"'), 'Int64') = ?)`,
			expectedError: nil,
		},
		{
			name: "Regexp operator - json body string",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.method",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorRegexp,
			value:         "GET|POST|PUT",
			expectedSQL:   `match(JSON_VALUE(body, '$."http"."method"'), ?)`,
			expectedError: nil,
		},
		{
			name: "Not Regexp operator - json body string",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "http.method",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorNotRegexp,
			value:         "DELETE|PATCH",
			expectedSQL:   `NOT match(JSON_VALUE(body, '$."http"."method"'), ?)`,
			expectedError: nil,
		},
		{
			name: "Regexp operator - json body with dots in path",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "user.email",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorRegexp,
			value:         "^.*@example\\.com$",
			expectedSQL:   `match(JSON_VALUE(body, '$."user"."email"'), ?)`,
			expectedError: nil,
		},
		{
			name: "Not Regexp operator - json body nested path",
			key: telemetrytypes.TelemetryFieldKey{
				Name:         "response.headers.content-type",
				FieldContext: telemetrytypes.FieldContextBody,
			},
			operator:      qbtypes.FilterOperatorNotRegexp,
			value:         "^text/.*",
			expectedSQL:   `NOT match(JSON_VALUE(body, '$."response"."headers"."content-type"'), ?)`,
			expectedError: nil,
		},
	}

	fl := flaggertest.New(t)
	fm := NewFieldMapper(fl)
	conditionBuilder := NewConditionBuilder(fm, fl)

	for _, tc := range testCases {
		sb := sqlbuilder.NewSelectBuilder()
		t.Run(tc.name, func(t *testing.T) {
			cond, err := conditionBuilder.conditionFor(ctx, 0, 0, &tc.key, tc.operator, tc.value, sb)
			sb.Where(cond)

			if tc.expectedError != nil {
				assert.Equal(t, tc.expectedError, err)
			} else {
				require.NoError(t, err)
				sql, _ := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
				assert.Contains(t, sql, tc.expectedSQL)
			}
		})
	}
}
