package repositories

import (
	"errors"
	"fmt"

	"gorm.io/gorm"

	"git.dynamicdiscord.de/kalipso/zineshop/models"
	"git.dynamicdiscord.de/kalipso/zineshop/utils"
)

type RegisterTokenRepository interface {
	Create() (models.RegisterToken, error)
	GetAll() ([]models.RegisterToken, error)
	Exists(string) (bool, error)
	Delete(string) error
}

type GORMRegisterTokenRepository struct {
	DB *gorm.DB
}

func NewGORMRegisterTokenRepository(db *gorm.DB) RegisterTokenRepository {
	return &GORMRegisterTokenRepository{
		DB: db,
	}
}

func (t *GORMRegisterTokenRepository) Create() (models.RegisterToken, error) {
	token := utils.GenerateToken()

	exists, err := t.Exists(token)
	if err != nil {
		return models.RegisterToken{}, err
	}

	if exists {
		return t.Create()
	}

	newToken := models.RegisterToken{
		Token: token,
	}
	result := t.DB.Create(&newToken)

	if result.Error != nil {
		return models.RegisterToken{}, result.Error
	}

	return newToken, nil
}

func (t *GORMRegisterTokenRepository) GetAll() ([]models.RegisterToken, error) {
	var tokens []models.RegisterToken
	result := t.DB.Find(&tokens)

	return tokens, result.Error
}

func (t *GORMRegisterTokenRepository) Exists(tokenString string) (bool, error) {
	var token models.RegisterToken
	result := t.DB.First(&token, "token = ?", tokenString)

	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return false, nil
		}

		return false, result.Error
	}

	return true, nil
}

func (t *GORMRegisterTokenRepository) Delete(token string) error {
	result := t.DB.Where("token = ?", token).Delete(&models.RegisterToken{})

	if result.Error != nil {
		return result.Error
	} else if result.RowsAffected == 0 {
		return fmt.Errorf("Token not found, could not be deleted")
	}

	return nil
}
