package rules

import (
	"encoding/json"
	"fmt"
	"strings"
	"testing"
)

func TestNewQueryStringPredicate(t *testing.T) {
	goodStr := "event_src_msg: \"act=2002910\""
	predicate := NewPredicate("", goodStr)

	if len(predicate.Operands) != 1 {
		t.Errorf("Got bad operands count. Expect 1, got %v", len(predicate.Operands))
	}

	operand, ok := predicate.Operands[0].(string)
	if !ok {
		t.Errorf("Bad operand type. Expect string, got %T", predicate.Operands[0])
	}

	if operand != goodStr {
		t.Errorf("Got bad operand. Expect %v, got %v", goodStr, operand)
	}
}

func TestParseQueryStringPredicate(t *testing.T) {
	goodStr := "event_src_msg: \\\"act=2002910\\\""
	predicateStr := fmt.Sprintf(`{"type": "%v", "field": "NULL", "operands": [ "%v" ]}`, "query_string", goodStr)

	var predicate Predicate
	err := json.Unmarshal([]byte(predicateStr), &predicate)

	if err != nil {
		t.Logf("%v", predicateStr)
		t.Errorf("%v", err)
		return
	}

	if len(predicate.Operands) != 1 {
		t.Errorf("Got bad operands count. Expect 1, got %v", len(predicate.Operands))
	}

	operand, ok := predicate.Operands[0].(string)
	if !ok {
		t.Errorf("Bad operand type. Expect string, got %T", predicate.Operands[0])
	}

	if operand != strings.Replace(goodStr, "\\", "", -1) {
		t.Errorf("Got bad operand. Expect \"%v\", got \"%v\"", goodStr, operand)
	}
}

func TestQueryStringToQuery(t *testing.T) {
	goodStr := "event_src_msg: \"act=2002910\""
	predicate := NewPredicate("", goodStr)

	data, err := json.Marshal(predicate)
	if err != nil {
		t.Errorf("%v", err)
		return
	}

	predicateStr := `{"field":"","operands":["event_src_msg: \"act=2002910\""]}`

	if string(data) != predicateStr {
		t.Errorf("Got bad predicate str. Expec %v, got %v", predicateStr, string(data))
	}
}

func TestQueryStringWillUseField(t *testing.T) {
	predicateStr := `{
 	"type": "query_string",
 	"field": "",
 	"operands": "event_protocol: \"TCP\" AND event_severity:>5"
	}`

	var predicate Predicate
	err := json.Unmarshal([]byte(predicateStr), &predicate)

	if err != nil {
		t.Logf("%v", predicateStr)
		t.Errorf("%v", err)
		return
	}

	if len(predicate.Operands) != 1 {
		t.Errorf("Got bad operands count. Expect 1, got %v", len(predicate.Operands))
	}

	_, ok := predicate.Operands[0].(string)
	if !ok {
		t.Errorf("Bad operand type. Expect string, got %T", predicate.Operands[0])
	}

}

func TestQueryStringFieldJson(t *testing.T) {
	predicate := NewPredicate("event_src_msg", "event_protocol: TCP")
	data, err := json.Marshal(predicate)
	if err != nil {
		t.Errorf("%v", err)
		return
	}

	predicateStr := `{"field":"event_src_msg","operands":["event_protocol: TCP"]}`

	if string(data) != predicateStr {
		t.Errorf("Got bad predicate str. Expec %v, got %v", predicateStr, string(data))
	}
}

func TestQueryStringFieldJsonEmpty(t *testing.T) {
	predicate := NewPredicate("", "event_protocol: TCP")

	data, err := json.Marshal(predicate)
	if err != nil {
		t.Errorf("%v", err)
		return
	}

	predicateStr := `{"field":"","operands":["event_protocol: TCP"]}`

	if string(data) != predicateStr {
		t.Errorf("Got bad predicate str. Expec %v, got %v", predicateStr, string(data))
	}
}

func TestQueryStringFieldSource(t *testing.T) {
	predicate := NewPredicate("event_src_msg", "event_protocol: TCP")

	src, err := predicate.Source()
	if err != nil {
		t.Errorf("%v", err)
		return
	}

	data, err := json.Marshal(src)
	if err != nil {
		t.Errorf("%v", err)
		return
	}

	predicateStr := `{"query_string":{"default_field":"event_src_msg","query":"event_protocol: TCP"}}`

	if string(data) != predicateStr {
		t.Errorf("Got bad predicate str. Expec %v, got %v", predicateStr, string(data))
	}
}

func TestQueryStringFieldSourceEmpty(t *testing.T) {
	predicate := NewPredicate("", "event_protocol: TCP")

	src, err := predicate.Source()
	if err != nil {
		t.Errorf("%v", err)
		return
	}

	data, err := json.Marshal(src)
	if err != nil {
		t.Errorf("%v", err)
		return
	}

	predicateStr := `{"query_string":{"query":"event_protocol: TCP"}}`

	if string(data) != predicateStr {
		t.Errorf("Got bad predicate str. Expec %v, got %v", predicateStr, string(data))
	}
}
