package main

import (
	"context"
	"fmt"
	"image"
	_ "image/jpeg"
	"image/png"
	"os"

	"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/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
	"golang.org/x/image/draw"
)

var sess = connectAWS()

func connectAWS() *session.Session {
	sess, err := session.NewSession(
		&aws.Config{Region: aws.String("eu-central-1")},
	)

	if err != nil {
		panic(err)
	}
	return sess
}

type Event struct {
	Image  string `json:image`
	Bucket string `json:bucket`
}

func DownloadImageFromS3(bucket, key, dest string) error {
	file, err := os.Create(dest)
	if err != nil {
		return err
	}
	defer file.Close()

	downloader := s3manager.NewDownloader(sess)
	_, err = downloader.Download(file,
		&s3.GetObjectInput{
			Bucket: aws.String(bucket),
			Key:    aws.String(key),
		})
	if err != nil {
		return err
	}

	return nil
}

func Resize(srcFile, dest string) error {
	input, _ := os.Open(srcFile)
	defer input.Close()

	output, _ := os.Create(dest)
	defer output.Close()

	// Decode the image
	src, _, err := image.Decode(input)
	if err != nil {
		return err
	}

	// Set the expected size that you want:
	dst := image.NewRGBA(image.Rect(0, 0, 400, 400))

	// Resize:
	draw.NearestNeighbor.Scale(dst, dst.Rect, src, src.Bounds(), draw.Over, nil)

	// Encode to `output`:
	png.Encode(output, dst)

	return nil
}

func Upload(src, dest, bucket string) error {
	input, _ := os.Open(src)
	defer input.Close()

	uploader := s3manager.NewUploader(sess)

	_, err := uploader.Upload(&s3manager.UploadInput{
		Bucket: aws.String(bucket), // Bucket to be used
		Key:    aws.String(dest),   // Name of the file to be saved
		Body:   input,              // File
	})

	return err
}

func HandleRequest(ctx context.Context, e Event) (Event, error) {
	if e.Image == "" {
		return e, nil
	}

	key := e.Image
	localPath := fmt.Sprintf("/tmp/%s", key)
	err := DownloadImageFromS3(e.Bucket, e.Image, localPath)
	if err != nil {
		fmt.Printf("Could not download image: %v\n", err)
		return Event{}, err
	}

	resizedPng := "/tmp/resized.png"
	err = Resize(localPath, resizedPng)
	if err != nil {
		fmt.Printf("Resize failed: %v\n", err)
		return Event{}, err
	}

	outputName := fmt.Sprintf("%s-thumb.png", key)
	err = Upload(resizedPng, outputName, e.Bucket)
	if err != nil {
		fmt.Printf("Upload failed: %v\n", err)
		return Event{}, err
	}

	return Event{outputName, e.Bucket}, nil
}

func main() {
	lambda.Start(HandleRequest)
}
