package cmd

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"

	eventbus "code.justin.tv/eventbus/client"
	"code.justin.tv/eventbus/client/testhelpers"
	"code.justin.tv/eventbus/express/parser/eventtypes"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/spf13/cobra"
)

var (
	filePath     string
	shipQueueURL string
)

func init() {
	rootCmd.AddCommand(shipCmd)

	shipCmd.Flags().StringVarP(&filePath, "file", "f", "", "When provided, restrict matches to this event type and allow filters to filter on event properties")
	shipCmd.Flags().StringVarP(&shipQueueURL, "queue-url", "u", "", "The queue to ship events to")

}

var shipCmd = &cobra.Command{
	Use:   "ship",
	Short: "Reads EventBus events from a file and ships them into a queue",
	Long: `
The file should contain a single JSON array, in the following format:

[
	{
		"event_type": "ClockUpdate",
		"payload": <JSON marshalled event>
	},
	{
		"event_type": "BitsUseCreate",
		"payload": <JSON marshalled event>
	}
]

Refer to the documentation for example JSON files.
	`,
	Run: func(cmd *cobra.Command, args []string) {
		data, err := ioutil.ReadFile(filePath)
		if err != nil {
			log.Fatal("Error reading ship input file: ", err)
		}

		var events []*event
		err = json.Unmarshal(data, &events)
		if err != nil {
			log.Fatal("Error parsing ship input file: ", err)
		}

		sess := session.Must(session.NewSession(aws.NewConfig().WithRegion("us-west-2")))
		sqsClient := sqs.New(sess)

		for _, event := range events {

			raw, err := testhelpers.MakePayload(&eventbus.Header{}, event.Payload)
			if err != nil {
				log.Fatal(err.Error())
			}

			snsMessage := raw.FakeSNSMessage()
			body, err := snsMessage.SQSBody()
			if err != nil {
				log.Fatal("Error generating SQS payload: ", err)
			}

			log.Println("Enqueuing event of type:", event.EventType)

			_, err = sqsClient.SendMessage(&sqs.SendMessageInput{
				QueueUrl:    aws.String(shipQueueURL),
				MessageBody: aws.String(body),
			})
			if err != nil {
				log.Fatal("Error enqueuing EventBus event onto SQS message: ", err)
			}
		}

	},
}

type event struct {
	EventType string           `json:"event_type"`
	Payload   eventbus.Message `json:"payload"`
}

func (e *event) UnmarshalJSON(b []byte) error {
	tmp := struct {
		EventType string          `json:"event_type"`
		Payload   json.RawMessage `json:"payload"`
	}{}

	err := json.Unmarshal(b, &tmp)
	if err != nil {
		return err
	}

	builder, ok := eventtypes.MessageBuilders[tmp.EventType]
	if !ok {
		return errors.New("invalid event type '" + tmp.EventType + "'")
	}

	msg := builder()

	err = json.Unmarshal(tmp.Payload, msg)
	if err != nil {
		return err
	}

	*e = event{
		EventType: tmp.EventType,
		Payload:   msg,
	}

	return nil
}
