package photoprism

import (
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/photoprism/photoprism/internal/config"
	"github.com/photoprism/photoprism/pkg/geo/s2"
)

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

	t.Run("IphoneSevenHeic", func(t *testing.T) {
		mediaFile, err := NewMediaFile(c.ExamplesPath() + "/iphone_7.heic")

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

		location, err := mediaFile.Location()

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

		if err = location.Find("places"); err != nil {
			t.Fatal(err)
		}

		// nominatim and photon disagree on Himeji (姫路市) and Takasago (高砂市), but both contain Shi.
		// The photo is within 90m of the boundary of the two cities.
		// And as this test is to validate Unicode, it's ok.
		assert.Contains(t, location.City(), "市")
		assert.Equal(t, "兵庫県", location.State())
		assert.Equal(t, "Japan", location.CountryName())
		assert.Equal(t, "", location.Category())
		assert.True(t, strings.HasPrefix(location.ID, s2.TokenPrefix+"3554df45"))
		location2, err := mediaFile.Location()

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

		if err = location.Find("places"); err != nil {
			t.Fatal(err)
		}

		assert.Contains(t, location2.City(), "市")
		assert.Equal(t, "兵庫県", location2.State())
	})
	t.Run("IphoneFifteenProHeic", func(t *testing.T) {
		mediaFile, err := NewMediaFile(c.ExamplesPath() + "/iphone_15_pro.heic")

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

		location, err := mediaFile.Location()

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

		if err = location.Find("places"); err != nil {
			t.Fatal(err)
		}

		assert.Equal(t, "Berlin", location.City())
		assert.Equal(t, "Berlin", location.State())
		assert.Equal(t, "Steglitz", location.District())
		assert.Equal(t, "Zimmermannstraße", location.Street())
		assert.Equal(t, "Germany", location.CountryName())
		assert.Equal(t, "", location.Category())

		location2, err := mediaFile.Location()

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

		if err = location.Find("places"); err != nil {
			t.Fatal(err)
		}

		assert.Equal(t, "Berlin", location2.City())
		assert.Equal(t, "Berlin", location2.State())
	})
	t.Run("IphoneXrJpg", func(t *testing.T) {
		mediaFile, err := NewMediaFile(c.ExamplesPath() + "/iphone_xr.jpg")

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

		location, err := mediaFile.Location()

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

		if err = location.Find("places"); err != nil {
			t.Fatal(err)
		}

		// Test Unicode and City is correct.
		assert.Equal(t, "白川村", location.City())
		assert.Equal(t, "岐阜県", location.State())
		assert.Equal(t, "Japan", location.CountryName())
		assert.Equal(t, "visitor center", location.Category())
		assert.True(t, strings.HasPrefix(location.ID, s2.TokenPrefix+"5ff871bf"))
		location2, err := mediaFile.Location()

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

		if err = location.Find("places"); err != nil {
			t.Fatal(err)
		}

		assert.Equal(t, "白川村", location2.City())
		assert.Equal(t, "岐阜県", location2.State())
	})
	t.Run("CatBrownJpg", func(t *testing.T) {
		f, err := NewMediaFile(c.ExamplesPath() + "/cat_brown.jpg")

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

		loc, err := f.Location()

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

		if err = loc.Find("places"); err != nil {
			t.Fatal(err)
		}

		assert.Equal(t, "Tübingen", loc.City())
		assert.Equal(t, "de", loc.CountryCode())
		assert.Equal(t, "Germany", loc.CountryName())
		assert.True(t, strings.HasPrefix(loc.ID, s2.TokenPrefix+"4799e4a5"))
	})
	t.Run("DogOrangeJpg", func(t *testing.T) {
		mediaFile, err := NewMediaFile(c.ExamplesPath() + "/dog_orange.jpg")

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

		if _, err := mediaFile.Location(); err == nil {
			t.Fatal("mediaFile.Location() should return error")
		} else {
			assert.Equal(t, "media: found no latitude and longitude", err.Error())
		}
	})
	t.Run("RandomDocx", func(t *testing.T) {
		mediaFile, err := NewMediaFile(c.ExamplesPath() + "/Random.docx")

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

		location, err := mediaFile.Location()

		assert.Error(t, err, "metadata: found no exif header in Random.docx")
		assert.Nil(t, location)
	})
}
