package plg_video_thumbnail

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"strings"

	. "github.com/mickael-kerjean/filestash/server/common"
)

const (
	VideoCachePath = "data/cache/video-thumbnail/"
)

var plugin_enable = func() bool {
	return Config.Get("features.video.enable_thumbnail").Schema(func(f *FormElement) *FormElement {
		if f == nil {
			f = &FormElement{}
		}
		f.Name = "enable_thumbnail"
		f.Type = "enable"
		f.Target = []string{}
		f.Description = "Enable/Disable on video thumbnail generation"
		f.Default = false
		return f
	}).Bool()
}

func init() {
	if _, err := exec.LookPath("ffmpeg"); err != nil {
		Hooks.Register.Onload(func() {
			Log.Warning("plg_video_thumbnail::init error=ffmpeg_not_installed")
		})
		return
	}

	Hooks.Register.Onload(func() {
		if plugin_enable() == false {
			return
		}
		cachePath := GetAbsolutePath(VideoCachePath)
		os.RemoveAll(cachePath)
		os.MkdirAll(cachePath, os.ModePerm)

		Hooks.Register.Thumbnailer("video/mp4", &ffmpegThumbnail{})
		Hooks.Register.Thumbnailer("video/x-matroska", &ffmpegThumbnail{})
		Hooks.Register.Thumbnailer("video/x-msvideo", &ffmpegThumbnail{})
	})
}

type ffmpegThumbnail struct{}

func (this *ffmpegThumbnail) Generate(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
	var (
		errBuff bytes.Buffer
		fullURL = strings.Replace(
			fmt.Sprintf("http://127.0.0.1:%d%s?%s", Config.Get("general.port").Int(), req.URL.Path, req.URL.RawQuery),
			"&thumbnail=true", "&origin=plg_video_thumbnail", 1,
		)
		cacheName = "thumb_" + GenerateID(ctx.Session) + "_" + QuickHash(req.URL.Query().Get("path"), 10) + ".jpeg"
		cachePath = GetAbsolutePath(VideoCachePath, cacheName)
	)

	reader.Close()
	thumbnail, err := os.OpenFile(cachePath, os.O_RDONLY, os.ModePerm)
	if err == nil {
		this.setHeader(res)
		return thumbnail, nil
	}

	cmd := exec.CommandContext(req.Context(), "ffmpeg", []string{
		"-hide_banner", "-headers", "cookie: " + req.Header.Get("Cookie") + "\r\n",
		"-skip_frame", "nokey",
		"-i", fullURL, "-y",
		"-an", "-sn",
		"-vf", "thumbnail, scale=320:320: force_original_aspect_ratio=decrease", "-fps_mode", "passthrough", "-frames:v", "1",
		"-c:v", "mjpeg", cachePath,
	}...)
	cmd.Stderr = &errBuff
	if err := cmd.Run(); err != nil {
		if req.Context().Err() == nil {
			Log.Debug("plg_video_thumbnail::generate::run path=%s err=%s", req.URL.Query().Get("path"), base64.StdEncoding.EncodeToString(errBuff.Bytes()))
			return nil, err
		}
		return nil, err
	}
	cmd.Wait()
	thumbnail, err = os.OpenFile(cachePath, os.O_RDONLY, os.ModePerm)
	if err != nil {
		Log.Error("plg_video_thumbnail::generate::open path=%s err=%s", cachePath, err.Error())
		return nil, err
	}
	this.setHeader(res)
	return thumbnail, nil
}

func (this *ffmpegThumbnail) setHeader(res *http.ResponseWriter) {
	(*res).Header().Set("Content-Type", "image/jpeg")
	(*res).Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", 3600*12))
}
