package User

import (
	"net/http"

	dto "astrology-api/dto/tarot"
	"astrology-api/helpers"
	"astrology-api/services"

	"github.com/gin-gonic/gin"
)

///////////////////////////////////////////////////////////
// Tarot Controller
///////////////////////////////////////////////////////////

// The tarot pages are public, like the rest of the reader: the catalogue is
// browsable and a reading only needs a name typed into a form. Nothing here
// reads user_id.

type TarotController struct {
	service services.TarotService
}

func NewTarotController(service services.TarotService) *TarotController {
	return &TarotController{service: service}
}

///////////////////////////////////////////////////////////
// Catalogue
///////////////////////////////////////////////////////////

// Cards is the deck. ?arcana=major|minor, ?suit=cups|wands|swords|pentacles and
// ?search= narrow it, which is all the major-arcana and minor-arcana pages need.
func (c *TarotController) Cards(ctx *gin.Context) {

	var request dto.TarotCardListRequest

	if err := ctx.ShouldBindQuery(&request); err != nil {

		ctx.JSON(http.StatusBadRequest, helpers.ErrorResponse(err.Error()))

		return
	}

	ctx.JSON(
		http.StatusOK,
		helpers.SuccessResponse("Tarot cards fetched successfully.", c.service.Catalogue(request)),
	)
}

// Card is one card's page. The interpretation is included by default, since a
// detail page wants it; ?with_reading=false gives the identity alone.
func (c *TarotController) Card(ctx *gin.Context) {

	withReading := ctx.Query("with_reading") != "false" && ctx.Query("with_reading") != "0"

	response, err := c.service.Card(
		ctx.Param("id"),
		ctx.Query("lang"),
		withReading,
	)

	if err != nil {

		ctx.JSON(http.StatusNotFound, helpers.ErrorResponse(err.Error()))

		return
	}

	ctx.JSON(
		http.StatusOK,
		helpers.SuccessResponse("Tarot card fetched successfully.", response),
	)
}

///////////////////////////////////////////////////////////
// Shuffle
///////////////////////////////////////////////////////////

// Shuffle deals the face-down spread the querent chooses from.
func (c *TarotController) Shuffle(ctx *gin.Context) {

	var request dto.TarotShuffleRequest

	if err := ctx.ShouldBindQuery(&request); err != nil {

		ctx.JSON(http.StatusBadRequest, helpers.ErrorResponse(err.Error()))

		return
	}

	response, err := c.service.Shuffle(request)

	if err != nil {

		ctx.JSON(http.StatusBadRequest, helpers.ErrorResponse(err.Error()))

		return
	}

	ctx.JSON(
		http.StatusOK,
		helpers.SuccessResponse("Tarot cards shuffled successfully.", response),
	)
}

///////////////////////////////////////////////////////////
// Readings
///////////////////////////////////////////////////////////

// reading runs one of the single-card spreads, which all bind the same request.
func (c *TarotController) reading(
	ctx *gin.Context,
	message string,
	run func(dto.TarotReadingRequest) (*dto.TarotReadingResponse, error),
) {

	var request dto.TarotReadingRequest

	if err := ctx.ShouldBindJSON(&request); err != nil {

		ctx.JSON(http.StatusBadRequest, helpers.ErrorResponse(err.Error()))

		return
	}

	response, err := run(request)

	if err != nil {

		ctx.JSON(http.StatusBadRequest, helpers.ErrorResponse(err.Error()))

		return
	}

	ctx.JSON(http.StatusOK, helpers.SuccessResponse(message, response))
}

func (c *TarotController) OneCard(ctx *gin.Context) {

	c.reading(ctx, "One card reading fetched successfully.", c.service.OneCard)
}

func (c *TarotController) YesNo(ctx *gin.Context) {

	c.reading(ctx, "Yes or no reading fetched successfully.", c.service.YesNo)
}

func (c *TarotController) Career(ctx *gin.Context) {

	c.reading(ctx, "Career reading fetched successfully.", c.service.Career)
}

func (c *TarotController) Love(ctx *gin.Context) {

	c.reading(ctx, "Love reading fetched successfully.", c.service.Love)
}

func (c *TarotController) ThreeCard(ctx *gin.Context) {

	var request dto.TarotThreeCardRequest

	if err := ctx.ShouldBindJSON(&request); err != nil {

		ctx.JSON(http.StatusBadRequest, helpers.ErrorResponse(err.Error()))

		return
	}

	response, err := c.service.ThreeCard(request)

	if err != nil {

		ctx.JSON(http.StatusBadRequest, helpers.ErrorResponse(err.Error()))

		return
	}

	ctx.JSON(
		http.StatusOK,
		helpers.SuccessResponse("Three card reading fetched successfully.", response),
	)
}

func (c *TarotController) LoveTriangle(ctx *gin.Context) {

	var request dto.TarotLoveTriangleRequest

	if err := ctx.ShouldBindJSON(&request); err != nil {

		ctx.JSON(http.StatusBadRequest, helpers.ErrorResponse(err.Error()))

		return
	}

	response, err := c.service.LoveTriangle(request)

	if err != nil {

		ctx.JSON(http.StatusBadRequest, helpers.ErrorResponse(err.Error()))

		return
	}

	ctx.JSON(
		http.StatusOK,
		helpers.SuccessResponse("Love triangle reading fetched successfully.", response),
	)
}

func (c *TarotController) Breakup(ctx *gin.Context) {

	var request dto.TarotBreakupRequest

	if err := ctx.ShouldBindJSON(&request); err != nil {

		ctx.JSON(http.StatusBadRequest, helpers.ErrorResponse(err.Error()))

		return
	}

	response, err := c.service.Breakup(request)

	if err != nil {

		ctx.JSON(http.StatusBadRequest, helpers.ErrorResponse(err.Error()))

		return
	}

	ctx.JSON(
		http.StatusOK,
		helpers.SuccessResponse("Breakup reading fetched successfully.", response),
	)
}

func (c *TarotController) FortuneCookie(ctx *gin.Context) {

	response, err := c.service.FortuneCookie(ctx.Query("lang"))

	if err != nil {

		ctx.JSON(http.StatusBadRequest, helpers.ErrorResponse(err.Error()))

		return
	}

	ctx.JSON(
		http.StatusOK,
		helpers.SuccessResponse("Fortune cookie fetched successfully.", response),
	)
}
