package handlers

import (
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"golang.org/x/crypto/bcrypt"

	"fishfish/database"
	"fishfish/models"
)

func Login(c *gin.Context) {
	jwtKey := []byte(os.Getenv("JWT_SECRET"))

	var input struct {
		Username string `json:"username"`
		Password string `json:"password"`
	}

	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Неверный ввод"})
		return
	}

	var user models.User

	err := database.DB.Where("username = ?", input.Username).First(&user).Error
	if err != nil {
		fmt.Printf("[LOGIN ERROR] Пользователь %s не найден в БД: Ошибка")
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Неверный логин или пароль"})
	}

	passErr := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(input.Password))

	if passErr != nil {
		fmt.Printf("[LOGIN ERROR] Пароль для пароля %s не совпал с хешем в базе данных")
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Неверный логин или пароль"})
		return
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"user_id": user.ID,
		"role":    user.Role,
		"exp":     time.Now().Add(time.Hour * 24).Unix(),
	})

	tokenString, _ := token.SignedString(jwtKey)

	c.JSON(http.StatusOK, gin.H{"token": tokenString, "user": gin.H{
		"id":         user.ID,
		"first_name": user.FirstName,
		"last_name":  user.LastName,
		"phone":      user.Phone,
		"role":       user.Role,
	}})
}

func Register(c *gin.Context) {
	var input struct {
		Username  string `json:"username" binding:"required"`
		Password  string `json:"password" binding:"required,min=8"`
		FirstName string `json:"first_name" binding:"required"`
		LastName  string `json:"last_name" binding:"required"`
		Phone     string `json:"phone"`
	}

	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ошибка валидации ", "details": err.Error()})
		return
	}

	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Ошибка при шифровании пароля"})
		return
	}

	// 3. Создаем объект пользователя
	user := models.User{
		Username:  input.Username,
		Password:  string(hashedPassword),
		FirstName: input.FirstName,
		LastName:  input.LastName,
		Phone:     input.Phone,
		Role:      "customer",
	}

	// 4. Сохраняем в базу через GORM
	if err := database.DB.Create(&user).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Ошибка при регистрации пользователя", "details": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "Пользователь успешно зарегистрирован"})
}

func RegisterAdmin(c *gin.Context) {
	var input struct {
		Username  string `json:"username" binding:"required"`
		Password  string `json:"password" binding:"required,min=8"`
		FirstName string `json:"first_name" binding:"required"`
		LastName  string `json:"last_name" binding:"required"`
		Phone     string `json:"phone"`
		Role      string `json:"role"`
	}

	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ошибка валидации ", "details": err.Error()})
		return
	}

	if input.Role != "Рабочий" && input.Role != "Админ" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Недопустимая роль"})
		return
	}

	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Ошибка при шифровании пароля"})
		return
	}

	user := models.User{
		Username:  input.Username,
		Password:  string(hashedPassword),
		FirstName: input.FirstName,
		LastName:  input.LastName,
		Phone:     input.Phone,
		Role:      input.Role,
	}

	if err := database.DB.Create(&user).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Ошибка при регистрации пользователя", "details": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "Пользователь успешно зарегистрирован"})
}

func UpdateProfile(c *gin.Context) {
	var input models.UpdateUserInput

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

	userID := c.MustGet("user_id")

	if err := database.DB.Model(&models.User{}).Where("id = ?", userID).Updates(models.User{
		FirstName: input.FirstName,
		LastName:  input.LastName,
		Phone:     input.Phone,
	}).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Не удалось обновить данные", "details": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Данные успешно обновлены"})
}

func GetUserInfo(c *gin.Context) {
	userID := c.MustGet("user_id")

	var user models.User

	if err := database.DB.First(&user, userID).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Ошибка при получение профиля"})
		return
	}

	c.JSON(http.StatusOK, user)
}
