package photoprism

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/photoprism/photoprism/internal/config"
	"github.com/photoprism/photoprism/internal/thumb"
)

func TestMediaFile_Thumbnail(t *testing.T) {
	conf := config.TestConfig()

	if err := conf.CreateDirectories(); err != nil {
		t.Error(err)
	}

	thumbsPath := conf.CachePath() + "/.test_mediafile_thumbnail"

	defer os.RemoveAll(thumbsPath)

	t.Run("ElephantsJpg", func(t *testing.T) {
		image, err := NewMediaFile(conf.ExamplesPath() + "/elephants.jpg")

		if err != nil {
			t.Fatal(err)
		}

		thumbnail, err := image.Thumbnail(thumbsPath, "tile_500")

		if err != nil {
			t.Fatal(err)
		}

		assert.FileExists(t, thumbnail)
	})
	t.Run("InvalidImageFormat", func(t *testing.T) {
		image, err := NewMediaFile(conf.ExamplesPath() + "/canon_eos_6d.xmp")

		if err != nil {
			t.Fatal(err)
		}

		thumbnail, err := image.Thumbnail(thumbsPath, "tile_500")

		assert.EqualError(t, err, "media: failed to create thumbnail for canon_eos_6d.xmp (image: unknown format)")

		t.Log(thumbnail)
	})
	t.Run("InvalidThumbnailType", func(t *testing.T) {
		image, err := NewMediaFile(conf.ExamplesPath() + "/elephants.jpg")

		if err != nil {
			t.Fatal(err)
		}

		thumbnail, err := image.Thumbnail(thumbsPath, "invalid_500")

		assert.EqualError(t, err, "media: invalid type invalid_500")

		t.Log(thumbnail)
	})
}

func TestMediaFile_Resample(t *testing.T) {
	conf := config.TestConfig()

	if err := conf.CreateDirectories(); err != nil {
		t.Error(err)
	}

	thumbsPath := conf.CachePath() + "/.test_mediafile_resample"

	defer func(path string) {
		_ = os.RemoveAll(path)
	}(thumbsPath)

	t.Run("ElephantsJpg", func(t *testing.T) {
		image, err := NewMediaFile(conf.ExamplesPath() + "/elephants.jpg")

		if err != nil {
			t.Fatal(err)
		}

		thumbnail, err := image.Resample(thumbsPath, thumb.Tile500)

		if err != nil {
			t.Fatal(err)
		}

		assert.NotEmpty(t, thumbnail)

	})
	t.Run("InvalidType", func(t *testing.T) {
		image, err := NewMediaFile(conf.ExamplesPath() + "/elephants.jpg")

		if err != nil {
			t.Fatal(err)
		}

		thumbnail, err := image.Resample(thumbsPath, "xxx_500")

		if err == nil {
			t.Fatal("err must not be nil")
		}

		assert.Equal(t, "media: invalid type xxx_500", err.Error())
		assert.Empty(t, thumbnail)
	})

}

func TestMediaFile_SkipThumbnailSize(t *testing.T) {
	t.Run("ElephantsJpg", func(t *testing.T) {
		m, err := NewMediaFile(filepath.Join(conf.ExamplesPath(), "elephants.jpg"))

		if err != nil {
			t.Fatal(err)
		}

		assert.False(t, m.SkipThumbnailSize(thumb.SizeColors))
		assert.False(t, m.SkipThumbnailSize(thumb.SizeTile100))
		assert.False(t, m.SkipThumbnailSize(thumb.SizeTile224))
		assert.False(t, m.SkipThumbnailSize(thumb.SizeTile500))
		assert.False(t, m.SkipThumbnailSize(thumb.SizeFit720))
		assert.True(t, m.SkipThumbnailSize(thumb.SizeFit1280))
		assert.True(t, m.SkipThumbnailSize(thumb.SizeFit1920))
	})
}

func TestMediaFile_GenerateThumbnails(t *testing.T) {
	c := config.TestConfig()

	thumbsPath := "./.test_mediafile_createthumbnails"

	if p, err := filepath.Abs(thumbsPath); err != nil {
		t.Fatal(err)
	} else {
		thumbsPath = p
	}

	defer func(path string) {
		_ = os.RemoveAll(path)
	}(thumbsPath)

	if err := c.CreateDirectories(); err != nil {
		t.Fatal(err)
	}

	t.Run("ElephantsJpg", func(t *testing.T) {
		m, err := NewMediaFile(filepath.Join(conf.ExamplesPath(), "elephants.jpg"))

		if err != nil {
			t.Fatal(err)
		}

		err = m.GenerateThumbnails(thumbsPath, true)

		if err != nil {
			t.Fatal(err)
		}

		thumbFilename, err := thumb.FileName(m.Hash(), thumbsPath, thumb.Sizes[thumb.Tile50].Width, thumb.Sizes[thumb.Tile50].Height, thumb.Sizes[thumb.Tile50].Options...)

		if err != nil {
			t.Fatal(err)
		}

		assert.FileExists(t, thumbFilename)
		assert.NoError(t, m.GenerateThumbnails(thumbsPath, false))
	})
	t.Run("AnimatedEarthJpg", func(t *testing.T) {
		m, err := NewMediaFile("testdata/animated-earth.jpg")

		if err != nil {
			t.Fatal(err)
		}

		err = m.GenerateThumbnails(thumbsPath, true)

		if err != nil {
			t.Fatal(err)
		}

		thumbFilename, err := thumb.FileName(m.Hash(), thumbsPath, thumb.Sizes[thumb.Tile50].Width, thumb.Sizes[thumb.Tile50].Height, thumb.Sizes[thumb.Tile50].Options...)

		if err != nil {
			t.Fatal(err)
		}

		assert.FileExists(t, thumbFilename)
		assert.NoError(t, m.GenerateThumbnails(thumbsPath, false))
	})
	t.Run("PhotoPrismPng", func(t *testing.T) {
		m, err := NewMediaFile("testdata/photoprism.png")

		if err != nil {
			t.Fatal(err)
		}

		err = m.GenerateThumbnails(thumbsPath, true)

		if err != nil {
			t.Fatal(err)
		}

		thumbFilename, err := thumb.FileName(m.Hash(), thumbsPath, thumb.Sizes[thumb.Tile50].Width, thumb.Sizes[thumb.Tile50].Height, thumb.Sizes[thumb.Tile50].Options...)

		if err != nil {
			t.Fatal(err)
		}

		assert.FileExists(t, thumbFilename)
		assert.NoError(t, m.GenerateThumbnails(thumbsPath, false))
	})
	t.Run("BrokenAnimatedEarthJpg", func(t *testing.T) {
		m, err := NewMediaFile("testdata/broken/animated-earth.jpg")

		if err != nil {
			t.Fatal(err)
		}

		err = m.GenerateThumbnails(thumbsPath, true)

		if err != nil {
			t.Fatal(err)
		}

		thumbFilename, err := thumb.FileName(m.Hash(), thumbsPath, thumb.Sizes[thumb.Tile50].Width, thumb.Sizes[thumb.Tile50].Height, thumb.Sizes[thumb.Tile50].Options...)

		if err != nil {
			t.Fatal(err)
		}

		assert.FileExists(t, thumbFilename)
		assert.NoError(t, m.GenerateThumbnails(thumbsPath, false))
	})
}

func TestMediaFile_ChangeOrientation(t *testing.T) {
	t.Run("JPEG", func(t *testing.T) {
		m, err := NewMediaFile("testdata/orientation.jpg")

		if err != nil {
			t.Fatal(err)
		}

		orig := m.Orientation()

		if err = m.ChangeOrientation(8); err != nil {
			t.Fatal(err)
		}

		if err = m.ChangeOrientation(orig); err != nil {
			t.Fatal(err)
		}
	})
	t.Run("PNG", func(t *testing.T) {
		m, err := NewMediaFile("testdata/orientation.png")

		if err != nil {
			t.Fatal(err)
		}

		orig := m.Orientation()

		if err = m.ChangeOrientation(8); err != nil {
			t.Fatal(err)
		}

		if err = m.ChangeOrientation(orig); err != nil {
			t.Fatal(err)
		}
	})
}
