package photo

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"

	"code.nonshy.com/nonshy/website/pkg/log"
)

// GifToMP4 converts the image into an mp4 gifv. Requires the `ffmpeg` program to be installed, or returns an error.
func GifToMP4(filename string, cfg *UploadConfig) error {
	var (
		gifSize int64
		mp4Size int64
	)

	// Write GIF to temp file
	fh, err := os.CreateTemp("", "nonshy-*.gif")
	if err != nil {
		return err
	}
	defer os.Remove(fh.Name())

	if n, err := fh.Write(cfg.Data); err != nil {
		return err
	} else {
		gifSize = int64(n)
		log.Debug("GifToMP4: written %d bytes to %s", gifSize, fh.Name())
	}

	// Prepare an mp4 tempfile to write to
	var mp4 = strings.TrimSuffix(fh.Name(), ".gif") + ".mp4"

	// Run ffmpeg
	command := []string{
		"ffmpeg",
		"-i", fh.Name(), // .gif name
		"-movflags", "faststart",
		"-pix_fmt", "yuv420p",
		"-vf", `scale=trunc(iw/2)*2:trunc(ih/2)*2`,
		mp4, // .mp4 name
	}
	log.Debug("GifToMP4: Run command: %s", command)
	cmd := exec.Command(command[0], command[1:]...)
	if stdoutErr, err := cmd.CombinedOutput(); err != nil {
		log.Error("ffmpeg failed:\n%s", stdoutErr)

		return fmt.Errorf("GIF conversion didn't work (ffmpeg might not be installed): %s", err)
	}

	// Make sure the output file isn't empty.
	if stat, err := os.Stat(mp4); !os.IsNotExist(err) {
		mp4Size = stat.Size()
		log.Debug("GifToMP4: stats of generated file %s: %d bytes", mp4, mp4Size)
		if stat.Size() == 0 {
			return errors.New("GIF conversion failed: output mp4 file was empty")
		}
	}

	// Place the .mp4 (not .gif) in the static/photos/ folder
	if !strings.HasSuffix(filename, ".mp4") {
		filename = strings.TrimSuffix(filename, ".gif") + ".mp4"
	}
	if path, err := EnsurePath(filename); err == nil {
		// Copy the mp4 tempfile into the right place
		srcFile, err := ioutil.ReadFile(mp4)
		if err != nil {
			return err
		}

		destFile, err := os.Create(path)
		if err != nil {
			return err
		}
		defer destFile.Close()

		w, err := destFile.Write(srcFile)

		log.Debug("GifToMP4: Copy tempfile %s => %s; w=%d err=%s", mp4, path, w, err)
	}

	log.Info("GifToMP4: converted GIF (%d bytes, %f MB) to MP4 (%d bytes, %f MB) for a %f%% savings",
		gifSize, float64(gifSize)/1024/1024,
		mp4Size, float64(mp4Size)/1024/1024,
		float64(gifSize)/float64(mp4Size),
	)

	return nil
}
