package api

import (
	"fmt"
	"image"
	"image/color"
	"net/http"
	"os"
	"path"
	"time"

	"github.com/disintegration/imaging"
	"github.com/gin-gonic/gin"

	"github.com/photoprism/photoprism/internal/entity"
	"github.com/photoprism/photoprism/internal/form"
	"github.com/photoprism/photoprism/internal/get"
	"github.com/photoprism/photoprism/internal/photoprism"
	"github.com/photoprism/photoprism/internal/search"
	"github.com/photoprism/photoprism/internal/thumb"
	"github.com/photoprism/photoprism/pkg/clean"
	"github.com/photoprism/photoprism/pkg/fs"
)

// SharePreview returns a link share preview image.
//
// GET /s/:token/:uid/preview
// TODO: Proof of concept, needs refactoring.
func SharePreview(router *gin.RouterGroup) {
	router.GET("/:token/:shared/preview", func(c *gin.Context) {
		conf := get.Config()

		token := clean.Token(c.Param("token"))
		shared := clean.Token(c.Param("shared"))
		links := entity.FindLinks(token, shared)

		if len(links) != 1 {
			log.Warn("share: invalid token (preview)")
			c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
			return
		}

		thumbPath := path.Join(conf.ThumbCachePath(), "share")

		if err := os.MkdirAll(thumbPath, fs.ModeDir); err != nil {
			log.Error(err)
			c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
			return
		}

		previewFilename := fmt.Sprintf("%s/%s.jpg", thumbPath, shared)
		yesterday := time.Now().Add(-24 * time.Hour)

		if info, err := os.Stat(previewFilename); err != nil {
			log.Debugf("share: creating new preview for %s", clean.Log(shared))
		} else if info.ModTime().After(yesterday) {
			log.Debugf("share: using cached preview for %s", clean.Log(shared))
			c.File(previewFilename)
			return
		} else if err := os.Remove(previewFilename); err != nil {
			log.Errorf("share: could not remove old preview of %s", clean.Log(shared))
			c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
			return
		}

		var f form.SearchPhotos

		// Covers may only contain public content in shared albums.
		f.Album = shared
		f.Public = true
		f.Private = false
		f.Hidden = false
		f.Archived = false
		f.Review = false
		f.Primary = true

		// Get first 12 album entries.
		f.Count = 12
		f.Order = "relevance"

		if err := f.ParseQueryString(); err != nil {
			log.Errorf("preview: %s", err)
			c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
			return
		}

		p, count, err := search.Photos(f)

		if err != nil {
			log.Error(err)
			c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
			return
		}

		if count == 0 {
			c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
			return
		} else if count < 12 {
			f := p[0]
			size, _ := thumb.Sizes[thumb.Fit720]

			fileName := photoprism.FileName(f.FileRoot, f.FileName)

			if !fs.FileExists(fileName) {
				log.Errorf("share: file %s is missing (preview)", clean.Log(f.FileName))
				c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
				return
			}

			thumbnail, err := thumb.FromFile(fileName, f.FileHash, conf.ThumbCachePath(), size.Width, size.Height, f.FileOrientation, size.Options...)

			if err != nil {
				log.Error(err)
				c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
				return
			}

			c.File(thumbnail)

			return
		}

		width := 908
		height := 680
		x := 0
		y := 0

		preview := imaging.New(width, height, color.NRGBA{255, 255, 255, 255})
		size, _ := thumb.Sizes[thumb.Tile224]

		for _, f := range p {
			fileName := photoprism.FileName(f.FileRoot, f.FileName)

			if !fs.FileExists(fileName) {
				log.Errorf("share: file %s is missing (preview)", clean.Log(f.FileName))
				c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
				return
			}

			thumbnail, err := thumb.FromFile(fileName, f.FileHash, conf.ThumbCachePath(), size.Width, size.Height, f.FileOrientation, size.Options...)

			if err != nil {
				log.Error(err)
				c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
				return
			}

			src, err := imaging.Open(thumbnail)

			if err != nil {
				log.Error(err)
				c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
				return
			}

			preview = imaging.Paste(preview, src, image.Pt(x, y))

			x += 228

			if x > width {
				x = 0
				y += 228
			}
		}

		// Save the resulting image as JPEG.
		err = imaging.Save(preview, previewFilename)

		if err != nil {
			log.Error(err)
			c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
			return
		}

		c.File(previewFilename)
	})
}
