package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"code.justin.tv/foundation/history-service/internal/queue"
	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ecs"
	"github.com/aws/aws-sdk-go/service/ecs/ecsiface"
	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/aws/aws-sdk-go/service/sqs/sqsiface"
)

type generateReportHandler struct {
	queue    sqsiface.SQSAPI
	queueURL string

	ecs         ecsiface.ECSAPI
	clusterName string
	taskDefn    string
	subnets     []*string
}

func (h *generateReportHandler) execute(ctx context.Context, e events.DynamoDBEvent) error {
	for _, record := range e.Records {
		if record.EventName != string(events.DynamoDBOperationTypeInsert) {
			log.Printf("no need to process event type: %s, ignoring event\n", record.EventName)
			continue
		}

		// Number returns string
		ts := record.Change.NewImage["timestamp"].Number()
		requestTimeEpoch, err := strconv.ParseInt(ts, 10, 64)
		if err != nil {
			return fmt.Errorf("invalid timestamp %s stored in dynamodb, must be int", ts)
		}
		reqTime := time.Unix(requestTimeEpoch, 0)

		// Process the remove event.
		req := &queue.GenerateUserReportMessage{
			UserID:    record.Change.NewImage["user_id"].String(),
			Timestamp: reqTime,
		}
		// Store info in sqs
		msg, err := json.Marshal(req)
		if err != nil {
			return err
		}

		log.Printf("sending sqs message '%s' to generate report of all audits to queue: %s\n", string(msg), h.queueURL)
		_, err = h.queue.SendMessageWithContext(ctx, &sqs.SendMessageInput{
			MessageBody: aws.String(string(msg)),
			QueueUrl:    aws.String(h.queueURL),
		})
		if err != nil {
			return err
		}

		log.Printf("starting ecs task '%s' to generate report for user: %s\n", h.taskDefn, req.UserID)
		// run ECS task
		output, err := h.ecs.RunTaskWithContext(ctx, &ecs.RunTaskInput{
			Cluster:    aws.String(h.clusterName),
			Count:      aws.Int64(1),
			LaunchType: aws.String("FARGATE"),
			NetworkConfiguration: &ecs.NetworkConfiguration{
				AwsvpcConfiguration: &ecs.AwsVpcConfiguration{
					Subnets: h.subnets,
				},
			},
			TaskDefinition: aws.String(h.taskDefn),
		})

		if err != nil {
			return err
		}

		if len(output.Failures) != 0 {
			failure := output.Failures[0]
			err = fmt.Errorf("failed to run task arn: %s, err: %s", aws.StringValue(failure.Arn), aws.StringValue(failure.Reason))
			return err
		}
		log.Printf("requested submitted to ecs task to generate report for user: %s\n", req.UserID)
	}

	log.Println("no more generate user report request found. existing")
	return nil
}

func main() {
	region, ok := os.LookupEnv("REGION")
	if !ok {
		region = "us-west-2"
	}
	queueURL, ok := os.LookupEnv("QUEUE_URL")
	if !ok {
		log.Fatal("environment variable 'QUEUE_URL' is not set")
	}

	clusterName, ok := os.LookupEnv("CLUSTER_NAME")
	if !ok {
		log.Fatal("environment variable 'CLUSTER_NAME' is not set")
	}

	taskDefn, ok := os.LookupEnv("TASK_DEFINITION_ARN")
	if !ok {
		log.Fatal("environment variable 'TASK_DEFINITION_ARN' is not set")
	}

	taskSubnets, ok := os.LookupEnv("SUBNETS")
	if !ok {
		log.Fatal("environment variable 'SUBNETS' is not set")
	}

	var subnets []*string
	for _, s := range strings.Split(taskSubnets, ",") {
		subnets = append(subnets, aws.String(s))
	}

	sess := session.Must(session.NewSession(&aws.Config{
		Region: aws.String(region),
	}))
	h := &generateReportHandler{
		ecs:         ecs.New(sess),
		queue:       sqs.New(sess),
		queueURL:    queueURL,
		clusterName: clusterName,
		taskDefn:    taskDefn,
		subnets:     subnets,
	}
	lambda.Start(h.execute)
}
