package msgfilter

import (
	"errors"
	"time"

	eventbus "code.justin.tv/eventbus/client"
	"code.justin.tv/eventbus/express/parser"
	"code.justin.tv/eventbus/express/parser/eventtypes"

	"github.com/antonmedv/expr"
	"github.com/antonmedv/expr/vm"
	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/gofrs/uuid"
)

func NewFilter(expression string, eventType string) (*MessageFilter, error) {
	exampleResult := example()
	if eventType != "" {
		if builder, ok := eventtypes.MessageBuilders[eventType]; ok {
			exampleResult.Payload = builder()
		}
	}
	prog, err := expr.Compile(expression, expr.Env(makeEnv(exampleResult)))
	if err != nil {
		return nil, err
	}
	return &MessageFilter{prog: prog}, nil
}

type MessageFilter struct {
	prog *vm.Program
}

func (f *MessageFilter) FilterOne(message *parser.ParseResult) (bool, error) {
	result, err := expr.Run(f.prog, makeEnv(message))
	if err != nil {
		return false, err
	}
	if r, ok := result.(bool); ok {
		return r, nil
	}
	return false, errors.New("Expression did not yield a bool?")
}

func makeEnv(r *parser.ParseResult) map[string]interface{} {
	c := map[string]interface{}{
		"SQS":           r.SQS,
		"SQSAttrs":      r.SQSAttrs,
		"ReceiveCount":  r.ReceiveCount,
		"FirstReceive":  r.FirstReceive,
		"HasSNSMessage": r.HasSNSMessage,
		"IsEventBus":    r.IsEventBus,
		"SNS":           r.SNS,
		"EventBusType":  r.EventBusType,
		"Payload":       r.Payload,

		// some computed fields
		"Age": int(time.Since(r.FirstReceive)),

		// now some shortened aliases
		"EventType": r.EventBusType,
		"P":         r.Payload,
	}
	addBaseEnv(c)
	return c
}

func addBaseEnv(c map[string]interface{}) {
	c["day"] = int(24 * time.Hour)
	c["hour"] = int(time.Hour)
	c["minute"] = int(time.Minute)
	c["second"] = int(time.Second)
}

func example() *parser.ParseResult {
	return &parser.ParseResult{
		SQS: &sqs.Message{},
		EventBus: &eventbus.RawMessage{
			Header: &eventbus.Header{
				MessageID:   uuid.Must(uuid.NewV4()),
				Environment: "production",
				CreatedAt:   time.Now(),
				EventType:   "FooCreate",
			},
		},
	}
}
