package services

import (
	"context"

	"quyun/v2/app/requests"
	"quyun/v2/database/models"
	"quyun/v2/pkg/consts"

	"github.com/pkg/errors"
	"go.ipao.vip/gen"
)

// @provider
type user struct{}

func (t *user) FindByID(ctx context.Context, userID int64) (*models.User, error) {
	tbl, query := models.UserQuery.QueryContext(ctx)

	model, err := query.Preload(tbl.OwnedTenant, tbl.Tenants).Where(tbl.ID.Eq(userID)).First()
	if err != nil {
		return nil, errors.Wrapf(err, "FindByID failed, %d", userID)
	}
	return model, nil
}

func (t *user) FindByUsername(ctx context.Context, username string) (*models.User, error) {
	tbl, query := models.UserQuery.QueryContext(ctx)

	model, err := query.Where(tbl.Username.Eq(username)).First()
	if err != nil {
		return nil, errors.Wrapf(err, "FindByUsername failed, %s", username)
	}
	return model, nil
}

func (t *user) Create(ctx context.Context, user *models.User) (*models.User, error) {
	if err := user.Create(ctx); err != nil {
		return nil, errors.Wrapf(err, "Create user failed, %s", user.Username)
	}
	return user, nil
}

// SetStatus
func (t *user) SetStatus(ctx context.Context, userID int64, status consts.UserStatus) error {
	m, err := t.FindByID(ctx, userID)
	if err != nil {
		return err
	}

	m.Status = status
	return m.Save(ctx)
}

type UserPageFilter struct {
	requests.Pagination
	requests.SortQueryFilter

	Username *string `query:"username"`
	TenantID *int64  `query:"tenant_id"`
}

// Page
func (t *user) Page(ctx context.Context, filter *UserPageFilter) (*requests.Pager, error) {
	tbl, query := models.UserQuery.QueryContext(ctx)

	conds := []gen.Condition{}
	if filter.Username != nil {
		conds = append(conds, tbl.Username.Like("%"+*filter.Username+"%"))
	}

	if filter.TenantID != nil {
		tuTbl, _ := models.TenantUserQuery.QueryContext(ctx)
		query = query.RightJoin(tuTbl, tuTbl.UserID.EqCol(tbl.ID))
		conds = append(conds, tuTbl.TenantID.Eq(*filter.TenantID))
	}

	filter.Pagination.Format()
	items, total, err := query.Where(conds...).Order(tbl.ID.Desc()).FindByPage(int(filter.Offset()), int(filter.Limit))
	if err != nil {
		return nil, err
	}

	return &requests.Pager{
		Pagination: filter.Pagination,
		Total:      total,
		Items:      items,
	}, nil
}
