package media

import (
	"fmt"
	"image"
	"io"
	"os"
	"path"
	"path/filepath"
)

func (ms *MediaSource) ThumbPath(m Media, size image.Rectangle) string {
	size = m.NormalizeSize(size)
	return thumbPath(size, m.Name)
}

func (ms *MediaSource) ThumbFilename(m Media, size image.Rectangle) string {
	size = m.NormalizeSize(size)
	return thumbFilename(ms.ThumbDir, size, m.Name)
}

func thumbFilename(dir string, size image.Rectangle, name string) string {
	return filepath.Join(dir, thumbPath(size, name))
}

func thumbPath(size image.Rectangle, name string) string {
	w := size.Dx()
	h := size.Dy()

	var ws, hs string

	if w != 0 {
		ws = fmt.Sprint(w)
	}
	if h != 0 {
		hs = fmt.Sprint(h)
	}

	thumbSlug := filepath.Join(fmt.Sprintf("%sx%s", ws, hs), name)
	return path.Join("", "media", thumbSlug)
}

func (ms *MediaSource) ThumbMax(m Media, maxDim int) (image.Rectangle, error) {
	width := m.Size.Dx()
	height := m.Size.Dy()

	if width == 0 && height == 0 {
		return m.Size, fmt.Errorf("invalid media")
	}

	if width > height {
		height = height * maxDim / width
		width = maxDim
	} else {
		width = width * maxDim / height
		height = maxDim
	}

	size := image.Rect(0, 0, width, height)
	actual, err := ms.Thumb(m, size)
	return actual, err
}

func (ms *MediaSource) HasThumb(m Media, size image.Rectangle) bool {
	fi, err := os.Stat(ms.ThumbFilename(m, size))
	if err != nil {
		return false
	}
	return m.Date().Before(fi.ModTime())
}

func (m Media) NormalizeSize(size image.Rectangle) image.Rectangle {
	return NormalizeSize(m.Size, size)
}

func (ms *MediaSource) Thumb(m Media, size image.Rectangle) (image.Rectangle, error) {
	size = m.NormalizeSize(size)

	if ms.HasThumb(m, size) {
		return size, nil
	}

	f, err := os.Open(m.FullName)
	if err != nil {
		return size, err
	}
	defer f.Close()

	return size, ms.thumbReader(f, m, size)
}

func (ms *MediaSource) thumbReader(r io.Reader, m Media, size image.Rectangle) error {
	size = m.NormalizeSize(size)

	switch m.Type {
	case TypeImage:
		img, _, err := image.Decode(r)
		if err != nil {
			return err
		}

		filename := ms.ThumbFilename(m, size)
		return ThumbImage(filename, img, size)
	case TypeVideo:
		return VideoEncode(m.FullName, size, ms.ThumbDir)

	default:
		return fmt.Errorf("cannot thumb media type %q", m.Type)
	}
}
