package services

import (
	"context"

	"quyun/v2/app/http/super/dto"
	"quyun/v2/app/requests"
	"quyun/v2/database/models"
	"quyun/v2/pkg/consts"

	"github.com/pkg/errors"
	"github.com/samber/lo"
	"github.com/sirupsen/logrus"
	"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)
}

// Page 用户分页查询（超级管理员侧）。
func (t *user) Page(ctx context.Context, filter *dto.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))
	}

	if filter.Status != nil {
		conds = append(conds, tbl.Status.Eq(*filter.Status))
	}

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

	items := lo.Map(users, func(model *models.User, _ int) *dto.UserItem {
		return &dto.UserItem{
			User:              model,
			StatusDescription: model.Status.Description(),
		}
	})

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

// UpdateStatus 更新用户状态（超级管理员侧）。
func (t *user) UpdateStatus(ctx context.Context, userID int64, status consts.UserStatus) error {
	logrus.WithField("user_id", userID).WithField("status", status).Info("update user status")

	m, err := t.FindByID(ctx, userID)
	if err != nil {
		return err
	}

	m.Status = status
	_, err = m.Update(ctx)
	if err != nil {
		return err
	}

	return nil
}

// Statistics 按状态统计用户数量（超级管理员侧）。
func (t *user) Statistics(ctx context.Context) ([]*dto.UserStatistics, error) {
	tbl, query := models.UserQuery.QueryContext(ctx)

	var statistics []*dto.UserStatistics
	err := query.Select(tbl.Status, tbl.ID.Count().As("count")).Group(tbl.Status).Scan(&statistics)
	if err != nil {
		return nil, err
	}

	return lo.Map(statistics, func(item *dto.UserStatistics, _ int) *dto.UserStatistics {
		item.StatusDescription = item.Status.Description()
		return item
	}), nil
}
