package model

import (
	"context"
	"time"

	"forge.cadoles.com/Cadoles/daddy/internal/orm"
	"github.com/jinzhu/gorm"
	"github.com/pkg/errors"
	errs "github.com/pkg/errors"
)

type UserRepository struct {
	db *gorm.DB
}

func (r *UserRepository) CreateOrConnectUser(ctx context.Context, email string) (*User, error) {
	user := &User{
		Email: email,
	}

	err := orm.WithTx(ctx, r.db, func(ctx context.Context, tx *gorm.DB) error {
		err := tx.Where("email = ?", email).FirstOrCreate(user).Error
		if err != nil {
			return errors.WithStack(err)
		}

		if err := tx.Model(user).UpdateColumn("connected_at", time.Now()).Error; err != nil {
			return errors.WithStack(err)
		}

		return nil
	})

	if err != nil {
		return nil, errors.Wrap(err, "could not create user")
	}

	return user, nil
}

func (r *UserRepository) FindUserByEmail(ctx context.Context, email string) (*User, error) {
	user := &User{
		Email: email,
	}

	err := r.db.Model(user).Preload("Workgroups").First(user, "email = ?", email).Error
	if err != nil {
		return nil, errors.Wrap(err, "could not find user")
	}

	return user, nil
}

func (r *UserRepository) UpdateUserByEmail(ctx context.Context, email string, changes *User) (*User, error) {
	user := &User{
		Email: email,
	}

	err := r.db.First(user, "email = ?", email).Error
	if err != nil {
		return nil, errors.Wrap(err, "could not find user")
	}

	if err := r.db.Model(user).Updates(changes).Error; err != nil {
		return nil, errors.Wrap(err, "could not update user")
	}

	return user, nil
}

func (r *UserRepository) Find(ctx context.Context, id string) (*User, error) {
	user := &User{}
	query := r.db.Model(user).Where("id = ?", id)

	if err := query.First(&user).Error; err != nil {
		return nil, errs.WithStack(err)
	}

	return user, nil
}

func (r *UserRepository) All(ctx context.Context) ([]*User, error) {
	users := make([]*User, 0)
	query := r.db.Model(&User{})

	if err := query.Find(&users).Error; err != nil {
		return nil, errs.WithStack(err)
	}

	return users, nil
}

func NewUserRepository(db *gorm.DB) *UserRepository {
	return &UserRepository{db}
}