package User

import (
	"net/http"
	"strings"

	dto "astrology-api/dto"
	"astrology-api/helpers"

	usermodel "astrology-api/models/usermodel"

	services "astrology-api/services"

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

func Register(c *gin.Context) {

	var req dto.RegisterRequest

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

		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	user := usermodel.User{
		Name:         req.Name,
		ContactNo:    req.ContactNo,
		Email:        req.Email,
		Password:     req.Password,
		BirthDate:    req.BirthDate,
		BirthTime:    req.BirthTime,
		BirthPlace:   req.BirthPlace,
		AddressLine1: req.AddressLine1,
		Location:     req.Location,
		Pincode:      req.Pincode,
		Gender:       req.Gender,
		CountryCode:  req.CountryCode,
	}

	// The handset fields travel separately: the push token goes on the user
	// row, the session details go to login_histories.
	result, err := services.RegisterUser(user, req.Device())

	if err != nil {

		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data":    result,
	})
}

func VerifyMobileOTP(c *gin.Context) {

	var req dto.VerifyMobileOTPRequest

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

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	if req.UserID == 0 && req.Mobile == "" {

		c.JSON(400, gin.H{
			"success": false,
			"message": "either userId or mobile is required",
		})

		return
	}

	response, err := services.VerifyMobileOTP(
		req.UserID,
		req.Mobile,
		req.OTP,
		req.DeviceToken,
		req.DeviceType,
	)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(200, response)
}

func VerifyEmailOTP(c *gin.Context) {

	var req dto.VerifyEmailOTPRequest

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

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	response, err := services.VerifyEmailOTP(
		req.UserID,
		req.Email,
		req.OTP,
	)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(200, response)
}

func Login(c *gin.Context) {

	var req dto.LoginRequest

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

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	response, err := services.Login(req)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(200, response)
}

func VerifyLoginOTP(c *gin.Context) {

	var req dto.VerifyLoginOTPRequest

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

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	response, err := services.VerifyLoginOTP(req)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(200, response)
}

func ResendOTP(c *gin.Context) {

	var req dto.ResendOTPRequest

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

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	response, err := services.ResendOTP(req.UserID)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(200, response)
}

func ForgotPassword(c *gin.Context) {

	var req dto.ForgotPasswordRequest

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

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	response, err := services.ForgotPassword(req)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(200, response)
}

func ResetPassword(c *gin.Context) {

	var req dto.ResetPasswordRequest

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

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	response, err := services.ResetPassword(req)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(200, response)
}

func RefreshToken(c *gin.Context) {

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

	response, err := services.RefreshUserToken(userID)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(200, response)

}

func Profile(c *gin.Context) {

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

	if !exists {
		c.JSON(401, gin.H{
			"success": false,
			"message": "Token not found. Please Login Again.",
		})
		return
	}

	userID := userIDValue.(uint)

	response, err := services.Profile(userID)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(200, response)
}

func Logout(c *gin.Context) {

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

	response, err := services.Logout(userID)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(200, response)

}

// UpdateDeviceToken refreshes the handset's FCM registration token for the
// logged-in customer. The app should call it from its token-refresh handler,
// not only at login — FCM rotates tokens, and a stale one leaves the account
// looking registered while receiving nothing.
//
// POST /api/user/device-token
func UpdateDeviceToken(c *gin.Context) {

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

	var req dto.UpdateDeviceTokenRequest

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

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	response, err := services.UpdateDeviceToken(userID, req)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(200, gin.H{
		"success": true,
		"message": "Device token updated successfully",
		"data":    response,
	})
}

func UpdateProfile(c *gin.Context) {

	var req dto.UpdateProfileRequest

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

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	response, err := services.UpdateProfile(req)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(200, response)
}

func UpdateUserStatus(c *gin.Context) {

	var req dto.UpdateUserStatusRequest

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

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})
		return
	}

	response, err := services.UpdateUserStatus(req)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})
		return
	}

	c.JSON(200, response)
}

func DeleteUser(c *gin.Context) {

	var req dto.DeleteUserRequest

	c.ShouldBindJSON(&req)

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

	response, err := services.DeleteUser(req, userID)

	if err != nil {

		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})

		return
	}

	c.JSON(200, response)
}

func UploadProfileImage(c *gin.Context) {

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

	file, err := c.FormFile("profile")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Please select profile image",
		})
		return
	}

	// Generate save path
	savePath, _, err := helpers.GenerateProfileImagePath(
		userID,
		file.Filename,
	)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": err.Error(),
		})
		return
	}

	// Save uploaded file
	if err := c.SaveUploadedFile(file, savePath); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": err.Error(),
		})
		return
	}

	// Build public image URL

	baseURL := "https://api.astrology.togwe.com"

	webPath := strings.ReplaceAll(savePath, "\\", "/")

	imageURL := baseURL + "/" + webPath

	// Save URL in database
	response, err := services.UploadProfileImage(
		userID,
		imageURL,
	)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, response)
}

func RemoveProfileImage(c *gin.Context) {

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

	response, err := services.RemoveProfileImage(userID)

	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, response)
}
