package Astrologer

import (
	"net/http"

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

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

///////////////////////////////////////////////////////////
// Horoscope Controller
///////////////////////////////////////////////////////////
//
// The astrologer app's horoscopes. Same paths, payloads and service as
// /api/user/horoscope/*, but the astrologer is never charged and the
// horoscope_requests row is logged against astrologers.id with
// actor_type = 'astrologer'.

type HoroscopeController struct {
	service services.HoroscopeService
}

func NewHoroscopeController(service services.HoroscopeService) *HoroscopeController {
	return &HoroscopeController{service: service}
}

// caller maps the token's users.id to astrologers.id and resolves the client
// (see services.ResolveHoroscopeClient).
func (c *HoroscopeController) caller(ctx *gin.Context, client dto.ClientInfo) (dto.HoroscopeCaller, bool) {

	userID := middleware.GetUserID(ctx)

	if userID == 0 {

		ctx.JSON(http.StatusUnauthorized, helpers.ErrorResponse("unauthorized"))

		return dto.HoroscopeCaller{}, false
	}

	astrologerID, err := c.service.AstrologerID(userID)

	if err != nil {

		ctx.JSON(http.StatusNotFound, helpers.ErrorResponse("astrologer not found"))

		return dto.HoroscopeCaller{}, false
	}

	caller := dto.HoroscopeCaller{
		UserID:       userID,
		AstrologerID: &astrologerID,
		ActorType:    services.HoroscopeActorAstrologer,
		IPAddress:    ctx.ClientIP(),
		Chargeable:   false,
	}

	services.ResolveHoroscopeClient(&caller, ctx.GetHeader, client, []string{
		services.HoroscopePlatformAstrologerApp,
		services.HoroscopePlatformAstrologerWeb,
	})

	return caller, true
}

// respondHoroscope writes the shared success / error envelope.
func respondHoroscope(ctx *gin.Context, message string, response *dto.VedicDataResponse, err error) {

	if err != nil {

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

		return
	}

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

///////////////////////////////////////////////////////////
// POST /api/astrologer/horoscope/daily
///////////////////////////////////////////////////////////

func (c *HoroscopeController) Daily(ctx *gin.Context) {

	var request dto.DailyHoroscopeRequest

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

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

		return
	}

	caller, ok := c.caller(ctx, request.ClientInfo)

	if !ok {
		return
	}

	response, err := c.service.Daily(caller, request)

	respondHoroscope(ctx, "Daily horoscope fetched successfully.", response, err)
}

///////////////////////////////////////////////////////////
// POST /api/astrologer/horoscope/daily-moon
///////////////////////////////////////////////////////////

func (c *HoroscopeController) DailyMoon(ctx *gin.Context) {

	var request dto.DailyHoroscopeRequest

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

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

		return
	}

	caller, ok := c.caller(ctx, request.ClientInfo)

	if !ok {
		return
	}

	response, err := c.service.DailyMoon(caller, request)

	respondHoroscope(ctx, "Daily moon horoscope fetched successfully.", response, err)
}

///////////////////////////////////////////////////////////
// POST /api/astrologer/horoscope/daily-nakshatra
///////////////////////////////////////////////////////////

func (c *HoroscopeController) DailyNakshatra(ctx *gin.Context) {

	var request dto.DailyNakshatraRequest

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

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

		return
	}

	caller, ok := c.caller(ctx, request.ClientInfo)

	if !ok {
		return
	}

	response, err := c.service.DailyNakshatra(caller, request)

	respondHoroscope(ctx, "Daily nakshatra fetched successfully.", response, err)
}

///////////////////////////////////////////////////////////
// POST /api/astrologer/horoscope/weekly
///////////////////////////////////////////////////////////

func (c *HoroscopeController) Weekly(ctx *gin.Context) {

	var request dto.WeeklyHoroscopeRequest

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

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

		return
	}

	caller, ok := c.caller(ctx, request.ClientInfo)

	if !ok {
		return
	}

	response, err := c.service.Weekly(caller, request)

	respondHoroscope(ctx, "Weekly horoscope fetched successfully.", response, err)
}

///////////////////////////////////////////////////////////
// POST /api/astrologer/horoscope/yearly
///////////////////////////////////////////////////////////

func (c *HoroscopeController) Yearly(ctx *gin.Context) {

	var request dto.YearlyHoroscopeRequest

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

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

		return
	}

	caller, ok := c.caller(ctx, request.ClientInfo)

	if !ok {
		return
	}

	response, err := c.service.Yearly(caller, request)

	respondHoroscope(ctx, "Yearly horoscope fetched successfully.", response, err)
}

///////////////////////////////////////////////////////////
// Signs
///////////////////////////////////////////////////////////

// Signs lists the zodiac signs for the sign picker. Send each sign's `zodiac`
// (1..12) to the prediction endpoints, never its `sign_id`.
func (c *HoroscopeController) Signs(ctx *gin.Context) {

	signs, err := c.service.Signs()

	if err != nil {

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

		return
	}

	ctx.JSON(http.StatusOK, helpers.SuccessResponse("Horoscope signs fetched successfully.", signs))
}
