package repository

import (
	"metazone.cc/metalab/internal/model"

	"gorm.io/gorm"
)

// UserRepo 用户数据访问
type UserRepo struct {
	db *gorm.DB
}

// NewUserRepo 构造函数
func NewUserRepo(db *gorm.DB) *UserRepo {
	return &UserRepo{db: db}
}

// Create 创建用户
func (r *UserRepo) Create(user *model.User) error {
	return r.db.Create(user).Error
}

// FindByEmail 按邮箱查找用户（含软删除，用于登录等需要找到已注销用户的场景）
func (r *UserRepo) FindByEmail(email string) (*model.User, error) {
	var user model.User
	err := r.db.Unscoped().Where("email = ?", email).First(&user).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// FindByID 按 UID 查找用户
func (r *UserRepo) FindByID(id uint) (*model.User, error) {
	var user model.User
	err := r.db.First(&user, id).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// FindByUsername 按用户名查找
func (r *UserRepo) FindByUsername(username string) (*model.User, error) {
	var user model.User
	err := r.db.Where("username = ?", username).First(&user).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// ExistsByEmail 检查邮箱是否已注册
func (r *UserRepo) ExistsByEmail(email string) (bool, error) {
	var count int64
	err := r.db.Model(&model.User{}).Where("email = ?", email).Count(&count).Error
	return count > 0, err
}

// ExistsByUsername 检查用户名是否已存在
func (r *UserRepo) ExistsByUsername(username string) (bool, error) {
	var count int64
	err := r.db.Model(&model.User{}).Where("username = ?", username).Count(&count).Error
	return count > 0, err
}

// ExistsByEmailExclude 检查邮箱是否被其他 active 用户占用（解锁前冲突检查）
func (r *UserRepo) ExistsByEmailExclude(email string, excludeUID uint) (bool, error) {
	var count int64
	err := r.db.Model(&model.User{}).
		Where("email = ? AND uid != ?", email, excludeUID).
		Count(&count).Error
	return count > 0, err
}

// FindByIDForAuth 认证专用查询：返回 uid/email/username/role/status
// 比 FindByID 轻量（不查 avatar、bio 等无用字段），避免全量 SELECT *
func (r *UserRepo) FindByIDForAuth(userID uint) (*model.User, error) {
	var user model.User
	err := r.db.Select("uid", "email", "username", "role", "status").
		First(&user, userID).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// FindByIDUnscoped 管理后台专用：含软删除用户，用于解锁/封禁等操作
func (r *UserRepo) FindByIDUnscoped(userID uint) (*model.User, error) {
	var user model.User
	err := r.db.Unscoped().Select("uid", "email", "username", "role", "status", "deleted_at").
		First(&user, userID).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// UpdateStatus 更新用户状态（含软删除用户，locked 状态变更需要）
func (r *UserRepo) UpdateStatus(uid uint, status string) error {
	return r.db.Unscoped().Model(&model.User{}).Where("uid = ?", uid).Update("status", status).Error
}

// UpdateRole 更新用户角色（仅 owner 调用）
func (r *UserRepo) UpdateRole(uid uint, role string) error {
	return r.db.Model(&model.User{}).Where("uid = ?", uid).Update("role", role).Error
}

// Update 全量更新用户信息
func (r *UserRepo) Update(user *model.User) error {
	return r.db.Save(user).Error
}

// SoftDelete GORM 软删除（设 DeletedAt），用于 locked 状态释放邮箱
func (r *UserRepo) SoftDelete(uid uint) error {
	return r.db.Where("uid = ?", uid).Delete(&model.User{}).Error
}

// Restore 恢复软删除（清 DeletedAt）
func (r *UserRepo) Restore(uid uint) error {
	return r.db.Unscoped().Model(&model.User{}).Where("uid = ?", uid).Update("deleted_at", nil).Error
}

// buildSearchQuery 构建搜索/筛选的公共查询条件
func (r *UserRepo) buildSearchQuery(keyword, role, status string) *gorm.DB {
	query := r.db.Unscoped().Model(&model.User{})
	if keyword != "" {
		like := "%" + keyword + "%"
		query = query.Where("email LIKE ? OR username LIKE ?", like, like)
	}
	if role != "" {
		query = query.Where("role = ?", role)
	}
	if status != "" {
		query = query.Where("status = ?", status)
	}
	return query
}

// SearchUsers 综合搜索（含软删除用户）
func (r *UserRepo) SearchUsers(keyword, role, status string, offset, limit int) ([]model.User, error) {
	var users []model.User
	err := r.buildSearchQuery(keyword, role, status).
		Order("uid ASC").Offset(offset).Limit(limit).Find(&users).Error
	return users, err
}

// CountSearchUsers 搜索结果总数（含软删除用户）
func (r *UserRepo) CountSearchUsers(keyword, role, status string) (int64, error) {
	var count int64
	err := r.buildSearchQuery(keyword, role, status).Count(&count).Error
	return count, err
}

