package scanner

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

	"github.com/pkg/errors"
)

func InitializeExecutableWorkers() {
	DarktableCli = newDarktableWorker()
	FfmpegCli = newFfmpegWorker()
}

var DarktableCli *DarktableWorker = nil
var FfmpegCli *FfmpegWorker = nil

type ExecutableWorker interface {
	Path() string
}

type DarktableWorker struct {
	path string
}

type FfmpegWorker struct {
	path string
}

func newDarktableWorker() *DarktableWorker {
	path, err := exec.LookPath("darktable-cli")
	if err != nil {
		log.Println("Executable worker not found: darktable")
	} else {
		version, err := exec.Command(path, "--version").Output()
		if err != nil {
			log.Printf("Error getting version of darktable: %s\n", err)
			return nil
		}

		log.Printf("Found executable worker: darktable (%s)\n", strings.Split(string(version), "\n")[0])

		return &DarktableWorker{
			path: path,
		}
	}

	return nil
}

func newFfmpegWorker() *FfmpegWorker {
	path, err := exec.LookPath("ffmpeg")
	if err != nil {
		log.Println("Executable worker not found: ffmpeg")
	} else {
		version, err := exec.Command(path, "-version").Output()
		if err != nil {
			log.Printf("Error getting version of ffmpeg: %s\n", err)
			return nil
		}

		log.Printf("Found executable worker: ffmpeg (%s)\n", strings.Split(string(version), "\n")[0])

		return &FfmpegWorker{
			path: path,
		}
	}

	return nil
}

func (worker *DarktableWorker) IsInstalled() bool {
	return worker != nil
}

func (worker *FfmpegWorker) IsInstalled() bool {
	return worker != nil
}

func (worker *DarktableWorker) EncodeJpeg(inputPath string, outputPath string, jpegQuality int) error {
	tmpDir, err := ioutil.TempDir("/tmp", "photoview-darktable")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(tmpDir)

	args := []string{
		inputPath,
		outputPath,
		"--core",
		"--conf",
		fmt.Sprintf("plugins/imageio/format/jpeg/quality=%d", jpegQuality),
		"--configdir",
		tmpDir,
	}

	cmd := exec.Command(worker.path, args...)

	if err := cmd.Run(); err != nil {
		return errors.Wrapf(err, "encoding image using: %s %v", worker.path, args)
	}

	return nil
}

func (worker *FfmpegWorker) EncodeMp4(inputPath string, outputPath string) error {
	args := []string{
		"-i",
		inputPath,
		"-vcodec", "h264",
		"-acodec", "aac",
		"-vf", "scale='min(1080,iw)':'min(1080,ih)':force_original_aspect_ratio=decrease",
		outputPath,
	}

	cmd := exec.Command(worker.path, args...)

	if err := cmd.Run(); err != nil {
		return errors.Wrapf(err, "encoding video using: %s", worker.path)
	}

	return nil
}

func (worker *FfmpegWorker) EncodeVideoThumbnail(inputPath string, outputPath string, mediaData *EncodeMediaData) error {

	metadata, err := mediaData.VideoMetadata()
	if err != nil {
		return errors.Wrapf(err, "get metadata to encode video thumbnail (%s)", inputPath)
	}

	thumbnailOffsetSeconds := fmt.Sprintf("%d", int(metadata.Format.DurationSeconds*0.25))

	args := []string{
		"-i",
		inputPath,
		"-vframes", "1", // output one frame
		"-an", // disable audio
		"-vf", "scale='min(1024,iw)':'min(1024,ih)':force_original_aspect_ratio=decrease",
		"-ss", thumbnailOffsetSeconds, // grab frame at time offset
		outputPath,
	}

	cmd := exec.Command(worker.path, args...)

	if err := cmd.Run(); err != nil {
		return errors.Wrapf(err, "encoding video using: %s", worker.path)
	}

	return nil
}
