package api

import (
	"errors"
	"net/http"

	"github.com/gin-gonic/gin"
	"gitlab.celogeek.com/photos/api/internal/photos/models"
	"gitlab.celogeek.com/photos/api/internal/photoserrors"
	"gopkg.in/validator.v2"
	"gorm.io/gorm"
)

type SignupOrLoginRequest struct {
	Login    string `validate:"min=3,max=40,regexp=^[a-zA-Z0-9]*$"`
	Password string `validate:"min=8,max=40"`
}

func (s *Service) Signup(c *gin.Context) {
	var account *SignupOrLoginRequest

	if err := c.ShouldBindJSON(&account); err != nil {
		s.Error(c, http.StatusBadRequest, err)
		return
	}
	if err := validator.Validate(account); err != nil {
		s.Error(c, http.StatusExpectationFailed, err)
		return
	}

	var accountExists int64
	if err := s.DB.Model(&models.Account{}).Where("login = ?", account.Login).Count(&accountExists).Error; err != nil {
		s.Error(c, http.StatusInternalServerError, err)
		return
	}
	if accountExists > 0 {
		s.Error(c, http.StatusConflict, photoserrors.ErrAccountExists)
		return
	}
	if err := s.DB.Create(models.NewAccount(account.Login, account.Password)).Error; err != nil {
		s.Error(c, http.StatusConflict, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"status": "success",
	})
}

func (s *Service) Login(c *gin.Context) {
	var account *SignupOrLoginRequest

	if err := c.ShouldBindJSON(&account); err != nil {
		s.Error(c, http.StatusBadRequest, err)
		return
	}

	session, err := models.NewSession(s.DB, account.Login, account.Password)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			s.Error(c, http.StatusNotFound, photoserrors.ErrAccountAuth)
		} else {
			s.Error(c, http.StatusInternalServerError, err)
		}
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"status": "success",
		"token":  session.Token,
	})
}

func (s *Service) Logout(c *gin.Context) {
	res := s.DB.Where("token = ?", c.GetString("token")).Delete(&models.Session{})
	if res.Error != nil {
		s.Error(c, http.StatusInternalServerError, res.Error)
		return
	}
	if res.RowsAffected == 0 {
		s.Error(c, http.StatusNotFound, photoserrors.ErrSessionNotFound)
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"status": "success",
	})
}