package controllers

import (
	"github.com/gofiber/fiber/v2"
	"cloud.google.com/go/storage"
	"fmt"
	"io"
	"context"
	"time"
	"log"
	"github.com/kolesa-team/go-webp/encoder"
	"github.com/kolesa-team/go-webp/webp"
	"image/jpeg"
	"image/png"
	"image"
	"os"
	"mime/multipart"
	"strings"
)

// GetTestingAPI method for create a new access token.
// @Description Create a new access token.
// @Summary create a new access token
// @Tags Token
// @Accept json
// @Produce json
// @Success 200 {string} status "ok"
// @Router /v1/testing [get]
func GetTestingAPI(c *fiber.Ctx) error {
	
	return c.JSON(fiber.Map{
		"error":        false,
		"msg":          nil,
		"access_token": "123456 testing",
	})
}

func UploadStorage(c *fiber.Ctx) error {

	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, time.Second*50)
	defer cancel()

	// os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "") // FILL IN WITH YOUR FILE PATH
	client, err := storage.NewClient(context.Background())
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}

	bucketName := "bajubaru"
	// projectID := "bajubaruid"
	uploadPath := "testing/"


	file, err := c.FormFile("image")
	if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "error": true,
            "msg":   err.Error(),
        })
    }

    // Get Buffer from file
    buffer, err := file.Open()
    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "error": true,
            "msg":   err.Error(),
        })
    }
    defer buffer.Close()


	wc := client.Bucket(bucketName).Object(uploadPath + file.Filename).NewWriter(ctx)
	if _, err := io.Copy(wc, buffer); err != nil {
		return fmt.Errorf("io.Copy: %v", err)
	}
	if err := wc.Close(); err != nil {
		return fmt.Errorf("Writer.Close: %v", err)
	}


	return c.JSON(fiber.Map{
		"error":        false,
		"msg":          nil,
		"status": "success",
	})

}

func ImageUploader(buffer multipart.File, filename string, uploadPath string) error {

	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, time.Second*50)
	defer cancel()

	// os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "") // FILL IN WITH YOUR FILE PATH
	client, err := storage.NewClient(context.Background())
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
		return err
	}

	bucketName := "bajubaru"

	wc := client.Bucket(bucketName).Object(uploadPath + "/" + filename).NewWriter(ctx)
	if _, err := io.Copy(wc, buffer); err != nil {
		return fmt.Errorf("io.Copy: %v", err)
	}
	if err := wc.Close(); err != nil {
		return fmt.Errorf("Writer.Close: %v", err)
	}


	return nil
}

func WebpUploader(buffer *os.File, filename string, uploadPath string) error {

	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, time.Second*50)
	defer cancel()

	// os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "") // FILL IN WITH YOUR FILE PATH
	client, err := storage.NewClient(context.Background())
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
		return err
	}

	bucketName := "bajubaru"


	wc := client.Bucket(bucketName).Object(uploadPath + "/" + filename).NewWriter(ctx)
	if _, err := io.Copy(wc, buffer); err != nil {
		return fmt.Errorf("io.Copy: %v", err)
	}
	if err := wc.Close(); err != nil {
		return fmt.Errorf("Writer.Close: %v", err)
	}


	return nil
}


func ImageWebP(c *fiber.Ctx) error {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	scene := c.FormValue("scene")

	log.Println(scene)

    if(strings.Compare(scene, "") == 0){

    	log.Println("mandatory field: scene")

    	return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "code": fiber.StatusBadRequest,
            "message": "Mandatory Field : Scene",
            "status": false,
            "data": nil,
        })
    }else if(strings.Compare(scene, "media") == 0 || 
    		strings.Compare(scene, "product-image") == 0 || 
    		strings.Compare(scene, "product-images") == 0 || 
    		strings.Compare(scene, "product-varian-images") == 0 || 
    		strings.Compare(scene, "profiles") == 0 || 
    		strings.Compare(scene, "testing") == 0){

	}else {
		log.Println("invalid scene value")
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "code": fiber.StatusBadRequest,
            "message": "Invalid scene value",
            "status": false,
            "data": nil,
        })
	}



	file, err := c.FormFile("image")

	log.Println(file)

	if err != nil {
		log.Println(err.Error())
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "code": fiber.StatusBadRequest,
            "message":   err.Error(),
            "status":   false,
            "data":   nil,
        })
    }


    contentType := file.Header["Content-Type"][0]
    if(strings.Compare(contentType, "image/png") != 0 && 
       strings.Compare(contentType, "image/jpg") != 0 && 
       strings.Compare(contentType, "image/jpeg") != 0){

       	log.Println("Invalid image type")

		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "code": fiber.StatusBadRequest,
            "message": "Invalid image type. only jpg, jpeg & png allowed",
            "status": false,
            "data": nil,
        })
	}

    c.SaveFile(file, fmt.Sprintf("temp-processing/%s", file.Filename))

    buffer, err := os.Open("temp-processing/"+file.Filename)
	if err != nil {
		os.Remove("temp-processing/"+file.Filename)
		log.Println(err.Error())
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "code": fiber.StatusBadRequest,
            "message": err.Error(),
            "status": false,
            "data": nil,
        })
	}

	var img image.Image

	if(strings.Compare(contentType, "image/jpg") == 0 || strings.Compare(contentType, "image/jpeg") == 0 ){
		img, err = jpeg.Decode(buffer)
		if err != nil {
			log.Println(err.Error())
			os.Remove("temp-processing/"+file.Filename)
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
	            "code": fiber.StatusBadRequest,
	            "message": err.Error(),
	            "status": false,
	            "data": nil,
	        })
		}
	}else if(strings.Compare(contentType, "image/png") == 0){
		img, err = png.Decode(buffer)
		if err != nil {
			log.Println(err.Error())
			os.Remove("temp-processing/"+file.Filename)
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
	            "code": fiber.StatusBadRequest,
	            "message": err.Error(),
	            "status": false,
	            "data": nil,
	        })
		}
	}else {
		log.Println("invalid content type")
		os.Remove("temp-processing/"+file.Filename)
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "code": fiber.StatusBadRequest,
            "message": "Invalid Content Type",
            "status": false,
            "data": nil,
        })
	}

	

	output, err := os.Create("temp-processing/"+file.Filename + ".webp")
	if err != nil {
		log.Println(err.Error())
		os.Remove("temp-processing/"+file.Filename)
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "code": fiber.StatusBadRequest,
            "message": err.Error(),
            "status": false,
            "data": nil,
        })
	}

	defer output.Close()

	options, err := encoder.NewLossyEncoderOptions(encoder.PresetDefault, 75)
	if err != nil {
		log.Println(err.Error())
		os.Remove("temp-processing/"+file.Filename)
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "code": fiber.StatusBadRequest,
            "message": err.Error(),
            "status": false,
            "data": nil,
        })
	}

	if err := webp.Encode(output, img, options); err != nil {
		log.Println(err.Error())
		os.Remove("temp-processing/"+file.Filename)
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "code": fiber.StatusBadRequest,
            "message": err.Error(),
            "status": false,
            "data": nil,
        })
	}

	webpfile, err := os.Open("temp-processing/"+file.Filename + ".webp")
	if err != nil {
		log.Println(err.Error())
		os.Remove("temp-processing/"+file.Filename)
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "code": fiber.StatusBadRequest,
            "message": err.Error(),
            "status": false,
            "data": nil,
        })
	}

	err = WebpUploader(webpfile, file.Filename + ".webp", scene)
	if err != nil {
		log.Println(err.Error())
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "code": fiber.StatusBadRequest,
            "message": err.Error(),
            "status": false,
            "data": nil,
        })
    }

    buffer, err = os.Open("temp-processing/"+file.Filename)
	if err != nil {
		log.Println(err.Error())
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "code": fiber.StatusBadRequest,
            "message": err.Error(),
            "status": false,
            "data": nil,
        })
	}

    err = WebpUploader(buffer, file.Filename, scene)
	if err != nil {
		log.Println(err.Error())
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "code": fiber.StatusBadRequest,
            "message": err.Error(),
            "status": false,
            "data": nil,
        })
    }

    os.Remove("temp-processing/"+file.Filename)
    os.Remove("temp-processing/"+file.Filename + ".webp")

	return c.JSON(fiber.Map{
        "code": 200,
        "message": "",
        "status": false,
        "data": map[string]string{
        	"filename": file.Filename,
        	"cloud_url" : "https://storage.googleapis.com/bajubaru/"+scene+"/"+file.Filename,
        	"webp_filename"  : file.Filename + ".webp",
        	"webp_cloud_url" : "https://storage.googleapis.com/bajubaru/"+scene+"/"+file.Filename + ".webp",
        },
    })
}
