package controllers

import (
	"fmt"

	"GoMembership/internal/constants"
	"GoMembership/internal/middlewares"
	"GoMembership/internal/models"
	"GoMembership/internal/services"

	"net/http"

	"github.com/gin-gonic/gin"

	"GoMembership/pkg/logger"
)

type UserController struct {
	Service            services.UserServiceInterface
	EmailService       *services.EmailService
	ConsentService     services.ConsentServiceInterface
	BankAccountService services.BankAccountServiceInterface
	MembershipService  services.MembershipServiceInterface
}

type RegistrationData struct {
	User models.User `json:"user"`
}

func (uc *UserController) CurrentUserHandler(c *gin.Context) {
	userIDString, ok := c.Get("user_id")
	if !ok || userIDString == nil {
		logger.Error.Printf("Error getting user_id from header")
	}
	userID := userIDString.(float64)
	user, err := uc.Service.GetUserByID(int64(userID))
	if err != nil {
		logger.Error.Printf("Error retrieving valid user: %v", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving user."})
		return
	}

	c.JSON(http.StatusOK, user.Safe())
}

func (uc *UserController) LogoutHandler(c *gin.Context) {
	// just clear the JWT cookie
	c.SetCookie("jwt", "", -1, "/", "", true, true)
	c.JSON(http.StatusOK, gin.H{"message": "Logged out successfully"})
}

func (uc *UserController) LoginHandler(c *gin.Context) {
	var input struct {
		Email    string `json:"email"`
		Password string `json:"password"`
	}

	if err := c.ShouldBindJSON(&input); err != nil {
		logger.Error.Printf("Couldn't decode input: %v", err.Error())
		c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode request data"})
		return
	}

	user, err := uc.Service.GetUserByEmail(input.Email)
	if err != nil {
		logger.Error.Printf("Error during user(%v) retrieval: %v\n", input.Email, err)
		c.JSON(http.StatusNotFound, gin.H{"error": "Couldn't find user"})
		return
	}

	ok, err := user.PasswordMatches(input.Password)
	if err != nil {

		logger.Error.Printf("Error during Password comparison: %v", err.Error())
		c.JSON(http.StatusInternalServerError, gin.H{"error": "couldn't calculate match"})
		return
	}
	if !ok {

		logger.Error.Printf("Wrong Password: %v %v", user.FirstName, user.LastName)
		c.JSON(http.StatusNotAcceptable, gin.H{"error": "Wrong Password"})
		return
	}

	token, err := middlewares.GenerateToken(user.ID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate JWT token"})
		return
	}

	c.SetCookie(
		"jwt",
		token,
		10*60, // 10 minutes
		"/",
		"",
		true,
		true,
	)

	c.JSON(http.StatusOK, gin.H{
		"message":   "Login successful",
		"set-token": token,
	})
}

func (uc *UserController) RegisterUser(c *gin.Context) {

	var regData RegistrationData

	if err := c.ShouldBindJSON(&regData); err != nil {
		logger.Error.Printf("Couldn't decode Userdata: %v", err)
		c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode userdata"})
		return
	}
	if regData.User.Membership.SubscriptionModel.Name == "" {
		logger.Error.Printf("No subscription model provided: %v", regData.User.Email)
		c.JSON(http.StatusNotAcceptable, gin.H{"error": "No subscription model provided"})
		return
	}

	selectedModel, err := uc.MembershipService.GetModelByName(&regData.User.Membership.SubscriptionModel.Name)
	if err != nil {
		logger.Error.Printf("%v:No subscription model found: %#v", regData.User.Email, err)
		c.JSON(http.StatusNotFound, gin.H{"error": "Not a valid subscription model"})
		return
	}
	regData.User.Membership.SubscriptionModel = *selectedModel
	// logger.Info.Printf("REGISTERING user: %#v", regData.User)

	regData.User.RoleID = constants.Roles.Member

	// Register User
	id, token, err := uc.Service.RegisterUser(&regData.User)
	if err != nil {
		logger.Error.Printf("Couldn't register User(%v): %v", regData.User.Email, err)
		c.JSON(int(id), gin.H{"error": fmt.Sprintf("Couldn't register User: %v", err)})
		return
	}
	regData.User.ID = id

	// Register Consents
	var consents = [2]models.Consent{
		{
			FirstName:   regData.User.FirstName,
			LastName:    regData.User.LastName,
			Email:       regData.User.Email,
			ConsentType: "TermsOfService",
		},
		{
			FirstName:   regData.User.FirstName,
			LastName:    regData.User.LastName,
			Email:       regData.User.Email,
			ConsentType: "Privacy",
		},
	}
	for _, consent := range consents {
		_, err = uc.ConsentService.RegisterConsent(&consent)
		if err != nil {
			logger.Error.Printf("%v, Couldn't register consent: %v", regData.User.Email, err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Couldn't register User-consent"})
			return
		}
	}

	// Send notifications
	if err := uc.EmailService.SendVerificationEmail(&regData.User, &token); err != nil {
		logger.Error.Printf("Failed to send email verification email to user(%v): %v", regData.User.Email, err)
		// Proceed without returning error since user registration is successful
	}

	// Notify admin of new user registration
	if err := uc.EmailService.SendRegistrationNotification(&regData.User); err != nil {
		logger.Error.Printf("Failed to notify admin of new user(%v) registration: %v", regData.User.Email, err)
		// Proceed without returning error since user registration is successful
	}
	c.JSON(http.StatusCreated, gin.H{
		"message": "Registration successuful",
		"id":      regData.User.ID,
	})
}

func (uc *UserController) VerifyMailHandler(c *gin.Context) {
	token := c.Query("token")
	if token == "" {
		logger.Error.Println("Missing token to verify mail")
		c.HTML(http.StatusBadRequest, "verification_error.html", gin.H{"ErrorMessage": "Missing token"})
		return
	}

	user, err := uc.Service.VerifyUser(&token)
	if err != nil {
		logger.Error.Printf("Cannot verify user: %v", err)
		c.HTML(http.StatusUnauthorized, "verification_error.html", gin.H{"ErrorMessage": "Emailadresse wurde schon bestätigt. Sollte dies nicht der Fall sein, wende Dich bitte an info@carsharing-hasloh.de."})
		return
	}
	logger.Info.Printf("User: %#v", user)

	uc.EmailService.SendWelcomeEmail(user)
	c.HTML(http.StatusOK, "verification_success.html", gin.H{"FirstName": user.FirstName})

}
