package main

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

	"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/dynamodb"
	"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
	"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface"
	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/aws/aws-sdk-go/service/sqs/sqsiface"
)

// SNSHardDeleteEvent user service delete event is described here
// https://git-aws.internal.justin.tv/web/users-service/blob/master/doc/publishedSNSEvents.md#hard_delete_user
type SNSHardDeleteEvent struct {
	UserID    string    `json:"user_id" `
	Timestamp time.Time `json:"timestamp"`
}

// pendingUserDeletion scheam of pending_user_deletion ddb table
type pendingUserDeletion struct {
	UserID      string `dynamodbav:"user_id"`
	RequestTime int64  `dynamodbav:"timestamp"`
	Requester   string `dynamodbav:"requester"`
	ExpiresAt   int64  `dynamodbav:"expires_at"`
}
type hardDeleteEventHandler struct {
	ddb       dynamodbiface.DynamoDBAPI
	queue     sqsiface.SQSAPI
	queueURL  string
	tableName string
	ttl       int64
}

func (h *hardDeleteEventHandler) handler(ctx context.Context, sqsEvent events.SQSEvent) error {
	for _, message := range sqsEvent.Records {
		log.Printf("The message %s for event source %s = %s \n", message.MessageId, message.EventSource, message.Body)
		event := new(SNSHardDeleteEvent)
		err := json.Unmarshal([]byte(message.Body), event)
		if err != nil {
			return err
		}
		log.Printf("Received hard delete notification from user service to delete userID: %s\n", event.UserID)

		item := &pendingUserDeletion{
			UserID:      event.UserID,
			RequestTime: event.Timestamp.Unix(),
			Requester:   "user-service-hard-delete-event",
			ExpiresAt:   event.Timestamp.Unix() + h.ttl,
		}
		av, err := dynamodbattribute.MarshalMap(item)
		if err != nil {
			return err
		}

		input := &dynamodb.PutItemInput{
			Item:      av,
			TableName: aws.String(h.tableName),
		}
		_, err = h.ddb.PutItemWithContext(ctx, input)
		if err != nil {
			return err
		}
		log.Printf("audit deletion has been scheduled for %s", time.Unix(item.ExpiresAt, 0))

		// delete message from queue
		_, err = h.queue.DeleteMessageWithContext(ctx, &sqs.DeleteMessageInput{
			ReceiptHandle: aws.String(message.ReceiptHandle),
			QueueUrl:      aws.String(h.queueURL),
		})
		if err != nil {
			return fmt.Errorf("Error deleting SQS Message(userID: %s): %s", event.UserID, err.Error())
		}
	}
	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")
	}

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

	var ttl int64
	var err error
	ttlString, ok := os.LookupEnv("TTL")
	if !ok {
		log.Fatal("environment variable 'TTL' is not set")
	}

	if ttl, err = strconv.ParseInt(ttlString, 10, 64); err != nil {
		log.Fatalf("invalid ttl: '%s' configured, must be a number", ttlString)
	}

	sess := session.Must(session.NewSession(&aws.Config{
		Region: aws.String(region),
	}))

	h := &hardDeleteEventHandler{
		ddb:       dynamodb.New(sess),
		queue:     sqs.New(sess),
		queueURL:  queueURL,
		tableName: tableName,
		ttl:       ttl,
	}

	lambda.Start(h.handler)
}
