package User

import (
	"net/http"
	"strconv"

	kundalidto "astrology-api/dto/kundali"

	"astrology-api/helpers"
	"astrology-api/services"

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

type KundaliController struct {
	kundaliService services.KundaliService
}

func NewKundaliController() *KundaliController {
	return &KundaliController{
		kundaliService: services.NewKundaliService(),
	}
}

// optionalUserID returns the authenticated user's id, or 0 when the request
// arrived on a public route. Kundali generation is free and open to guests, so
// the absence of a session is not an error here.
func optionalUserID(c *gin.Context) uint {

	value, exists := c.Get("user_id")

	if !exists {
		return 0
	}

	userID, ok := value.(uint)

	if !ok {
		return 0
	}

	return userID
}

// AddKundali generates a complete kundali for every person in the request.

func (kc *KundaliController) AddKundali(c *gin.Context) {

	var req kundalidto.AddKundaliRequest

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   true,
			"message": err.Error(),
			"status":  400,
		})
		return
	}

	if len(req.Kundali) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   true,
			"message": "kundali data is required",
			"status":  400,
		})
		return
	}

	for _, k := range req.Kundali {

		if k.Name == "" {
			c.JSON(http.StatusBadRequest, gin.H{
				"error":   true,
				"message": "name is required",
				"status":  400,
			})
			return
		}

		if k.BirthDate == "" {
			c.JSON(http.StatusBadRequest, gin.H{
				"error":   true,
				"message": "birthDate is required",
				"status":  400,
			})
			return
		}

		if k.BirthTime == "" {
			c.JSON(http.StatusBadRequest, gin.H{
				"error":   true,
				"message": "birthTime is required",
				"status":  400,
			})
			return
		}

		if k.BirthPlace == "" {
			c.JSON(http.StatusBadRequest, gin.H{
				"error":   true,
				"message": "birthPlace is required",
				"status":  400,
			})
			return
		}

		if k.Latitude == 0 && k.Longitude == 0 {
			c.JSON(http.StatusBadRequest, gin.H{
				"error":   true,
				"message": "latitude and longitude are required",
				"status":  400,
			})
			return
		}
	}

	response, err := kc.kundaliService.AddKundali(
		optionalUserID(c),
		&req,
	)

	if err != nil {

		c.JSON(http.StatusBadRequest, gin.H{
			"error":   true,
			"message": err.Error(),
			"status":  400,
		})

		return
	}

	c.JSON(http.StatusOK, gin.H{
		"message":          response.Message,
		"recordList":       response.RecordList,
		"complete_details": response.CompleteDetails,
		"status":           response.Status,
	})
}

// ChartImage proxies a chart from VedicAstroAPI. The apps must not call the
// vendor directly: its chart URLs carry our API key in the query string.
func (kc *KundaliController) ChartImage(c *gin.Context) {

	var req kundalidto.ChartImageRequest

	if err := c.ShouldBindQuery(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   true,
			"message": err.Error(),
			"status":  400,
		})
		return
	}

	image, err := kc.kundaliService.ChartImage(req)

	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   true,
			"message": err.Error(),
			"status":  400,
		})
		return
	}

	c.Header("Cache-Control", "public, max-age=86400")

	c.Data(http.StatusOK, image.ContentType, image.Body)
}

func (kc *KundaliController) DownloadKundali(c *gin.Context) {

	kundaliID, err := parseIDParam(c, "id")

	if err != nil {

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

		return
	}

	userID := c.MustGet("user_id").(uint)

	response, err := kc.kundaliService.DownloadKundali(userID, kundaliID)

	if err != nil {

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

		return
	}

	c.JSON(
		http.StatusOK,
		helpers.SuccessResponse("Kundali pdf fetched successfully.", response),
	)
}

func (kc *KundaliController) GetKundalis(c *gin.Context) {

	userIDValue, exists := c.Get("user_id")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{
			"error":   true,
			"message": "Unauthorized",
			"status":  401,
		})
		return
	}

	userID, ok := userIDValue.(uint)
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{
			"error":   true,
			"message": "Invalid user session",
			"status":  401,
		})
		return
	}

	var req kundalidto.GetKundaliRequest

	if err := c.ShouldBindJSON(&req); err != nil {
		req.S = ""
	}

	response, err := kc.kundaliService.GetKundalis(
		userID,
		&req,
	)

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error":   true,
			"message": err.Error(),
			"status":  500,
		})
		return
	}

	c.JSON(http.StatusOK, response)
}

func (kc *KundaliController) ShowKundali(c *gin.Context) {

	userIDValue, exists := c.Get("user_id")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{
			"error":   true,
			"message": "Unauthorized",
			"status":  401,
		})
		return
	}

	userID := userIDValue.(uint)

	idParam := c.Param("id")

	kundaliID, err := strconv.ParseUint(
		idParam,
		10,
		64,
	)

	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   true,
			"message": "Invalid kundali id",
			"status":  400,
		})
		return
	}

	response, err := kc.kundaliService.ShowKundali(
		userID,
		uint(kundaliID),
	)

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error":   true,
			"message": err.Error(),
			"status":  500,
		})
		return
	}

	c.JSON(http.StatusOK, response)
}

func (kc *KundaliController) UpdateKundali(c *gin.Context) {

	userIDValue, exists := c.Get("user_id")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{
			"error":   true,
			"message": "Unauthorized",
			"status":  401,
		})
		return
	}

	userID := userIDValue.(uint)

	idParam := c.Param("id")

	kundaliID, err := strconv.ParseUint(
		idParam,
		10,
		64,
	)

	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   true,
			"message": "Invalid kundali id",
			"status":  400,
		})
		return
	}

	var req kundalidto.UpdateKundaliRequest

	if err := c.ShouldBindJSON(&req); err != nil {

		c.JSON(http.StatusBadRequest, gin.H{
			"error":   true,
			"message": err.Error(),
			"status":  400,
		})

		return
	}

	response, err := kc.kundaliService.UpdateKundali(
		userID,
		uint(kundaliID),
		&req,
	)

	if err != nil {

		c.JSON(http.StatusBadRequest, gin.H{
			"error":   true,
			"message": err.Error(),
			"status":  400,
		})

		return
	}

	c.JSON(http.StatusOK, response)
}

func (kc *KundaliController) DeleteKundali(c *gin.Context) {

	userIDValue, exists := c.Get("user_id")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{
			"error":   true,
			"message": "Unauthorized",
			"status":  401,
		})
		return
	}

	userID := userIDValue.(uint)

	var req kundalidto.DeleteKundaliRequest

	if err := c.ShouldBindJSON(&req); err != nil {

		c.JSON(http.StatusBadRequest, gin.H{
			"error":   true,
			"message": err.Error(),
			"status":  400,
		})

		return
	}

	response, err := kc.kundaliService.DeleteKundali(
		userID,
		&req,
	)

	if err != nil {

		c.JSON(http.StatusBadRequest, gin.H{
			"error":   true,
			"message": err.Error(),
			"status":  400,
		})

		return
	}

	c.JSON(http.StatusOK, response)
}
