package api

import (
	"net/http"

	"github.com/gin-gonic/gin"

	"github.com/photoprism/photoprism/internal/auth/acl"
	"github.com/photoprism/photoprism/internal/entity/query"
	"github.com/photoprism/photoprism/internal/form"
	"github.com/photoprism/photoprism/internal/photoprism"
	"github.com/photoprism/photoprism/internal/photoprism/get"
	"github.com/photoprism/photoprism/pkg/clean"
	"github.com/photoprism/photoprism/pkg/i18n"
)

// ChangeFileOrientation changes the orientation of a file.
//
//	@Summary	changes the orientation of a file
//	@Id			ChangeFileOrientation
//	@Tags		Files
//	@Accept		json
//	@Produce	json
//	@Success	200						{object}	entity.Photo
//	@Failure	400,401,403,404,429,500	{object}	i18n.Response
//	@Param		uid						path		string		true	"photo uid"
//	@Param		fileuid					path		string		true	"file uid"
//	@Param		file					body		form.File	true	"file orientation"
//	@Router		/api/v1/photos/{uid}/files/{fileuid}/orientation [put]
func ChangeFileOrientation(router *gin.RouterGroup) {
	router.PUT("/photos/:uid/files/:file_uid/orientation", func(c *gin.Context) {
		s := Auth(c, acl.ResourceFiles, acl.ActionUpdate)

		if s.Abort(c) {
			return
		}

		conf := get.Config()

		// Abort in read-only mode or if editing is disabled.
		if conf.ReadOnly() || !conf.Settings().Features.Edit {
			c.AbortWithStatusJSON(http.StatusForbidden, i18n.NewResponse(http.StatusForbidden, i18n.ErrReadOnly))
			return
		} else if conf.DisableExifTool() {
			c.AbortWithStatusJSON(http.StatusInternalServerError, "exiftool is disabled")
			return
		}

		fileUid := clean.UID(c.Param("file_uid"))

		m, err := query.FileByUID(fileUid)

		// Abort if the file was not found.
		if err != nil {
			log.Errorf("files: %s (change orientation)", err)
			AbortEntityNotFound(c)
			return
		}

		// Init form with model values
		frm, err := form.NewFile(m)

		if err != nil {
			Abort(c, http.StatusInternalServerError, i18n.ErrSaveFailed)
			return
		}

		// Assign and validate request form values.
		if err = c.BindJSON(&frm); err != nil {
			Abort(c, http.StatusBadRequest, i18n.ErrBadRequest)
			return
		}

		// Update orientation if it was changed.
		if m.Orientation() != frm.Orientation() {
			fileName := photoprism.FileName(m.FileRoot, m.FileName)
			mf, fileErr := photoprism.NewMediaFile(fileName)

			// Check if file exists.
			if fileErr != nil {
				Abort(c, http.StatusInternalServerError, i18n.ErrFileNotFound)
				return
			}

			// Update file header.
			if fileErr = mf.ChangeOrientation(frm.Orientation()); fileErr != nil {
				log.Debugf("file: %s in %s (change orientation)", fileErr, clean.Log(mf.BaseName()))
				Abort(c, http.StatusInternalServerError, i18n.ErrSaveFailed)
				return
			}

			// Update index.
			ind := get.Index()
			if res := ind.FileName(mf.FileName(), photoprism.IndexOptionsSingle(conf)); res.Failed() {
				log.Errorf("file: %s in %s (change orientation)", res.Err, clean.Log(mf.BaseName()))
				AbortSaveFailed(c)
				return
			}
		}

		// Return updated photo.
		p, err := query.PhotoPreloadByUID(m.PhotoUID)

		if err != nil {
			AbortEntityNotFound(c)
			return
		}

		PublishPhotoEvent(StatusUpdated, m.PhotoUID, c)

		c.JSON(http.StatusOK, p)
	})
}
