// Package dao 提供 auth 模块的数据库访问操作
package dao

import (
	"context"

	"github.com/echochat/backend/app/auth/model"
	"github.com/echochat/backend/pkg/logs"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

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

// NewUserDAO 创建 UserDAO 实例
func NewUserDAO(db *gorm.DB) *UserDAO {
	return &UserDAO{db: db}
}

// Create 创建用户
// 插入一条新用户记录，username 和 email 有唯一索引
func (d *UserDAO) Create(ctx context.Context, user *model.User) error {
	funcName := "dao.user_dao.Create"
	logs.Info(ctx, funcName, "创建用户",
		zap.String("username", user.Username),
		zap.String("email", logs.MaskEmail(user.Email)),
	)

	var err error
	defer func() {
		if err != nil {
			logs.Error(ctx, funcName, "创建用户失败", zap.Error(err))
		} else {
			logs.Info(ctx, funcName, "创建用户成功", zap.Int64("user_id", user.ID))
		}
	}()

	err = d.db.WithContext(ctx).Create(user).Error
	return err
}

// FindByEmail 按邮箱查询用户
// 精确匹配邮箱地址，利用 email 唯一索引
func (d *UserDAO) FindByEmail(ctx context.Context, email string) (*model.User, error) {
	funcName := "dao.user_dao.FindByEmail"
	logs.Debug(ctx, funcName, "按邮箱查询用户", zap.String("email", logs.MaskEmail(email)))

	var user model.User
	err := d.db.WithContext(ctx).Where("email = ?", email).First(&user).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// FindByUsername 按用户名查询用户
// 精确匹配用户名，利用 username 唯一索引
func (d *UserDAO) FindByUsername(ctx context.Context, username string) (*model.User, error) {
	funcName := "dao.user_dao.FindByUsername"
	logs.Debug(ctx, funcName, "按用户名查询用户", zap.String("username", username))

	var user model.User
	err := d.db.WithContext(ctx).Where("username = ?", username).First(&user).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// FindByID 按 ID 查询用户
func (d *UserDAO) FindByID(ctx context.Context, id int64) (*model.User, error) {
	funcName := "dao.user_dao.FindByID"
	logs.Debug(ctx, funcName, "按ID查询用户", zap.Int64("id", id))

	var user model.User
	err := d.db.WithContext(ctx).First(&user, id).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// Update 更新用户信息
// 仅更新非零值字段
func (d *UserDAO) Update(ctx context.Context, user *model.User) error {
	funcName := "dao.user_dao.Update"
	logs.Info(ctx, funcName, "更新用户信息", zap.Int64("user_id", user.ID))

	var err error
	defer func() {
		if err != nil {
			logs.Error(ctx, funcName, "更新用户失败", zap.Int64("user_id", user.ID), zap.Error(err))
		}
	}()

	err = d.db.WithContext(ctx).Save(user).Error
	return err
}

// UpdateLastLogin 更新最后登录信息
func (d *UserDAO) UpdateLastLogin(ctx context.Context, userID int64, ip string) error {
	funcName := "dao.user_dao.UpdateLastLogin"
	logs.Debug(ctx, funcName, "更新登录信息", zap.Int64("user_id", userID))

	err := d.db.WithContext(ctx).
		Model(&model.User{}).
		Where("id = ?", userID).
		Updates(map[string]interface{}{
			"last_login_at": gorm.Expr("NOW()"),
			"last_login_ip": ip,
		}).Error
	return err
}

// FindByIDs 批量按 ID 查询用户
func (d *UserDAO) FindByIDs(ctx context.Context, ids []int64) ([]model.User, error) {
	funcName := "dao.user_dao.FindByIDs"
	logs.Debug(ctx, funcName, "批量查询用户", zap.Int("count", len(ids)))

	var users []model.User
	err := d.db.WithContext(ctx).Where("id IN ?", ids).Find(&users).Error
	if err != nil {
		logs.Error(ctx, funcName, "批量查询用户失败", zap.Error(err))
		return nil, err
	}
	return users, nil
}

// FindByAccount 按用户名或邮箱查找用户（登录时使用）
func (d *UserDAO) FindByAccount(ctx context.Context, account string) (*model.User, error) {
	funcName := "dao.user_dao.FindByAccount"
	logs.Debug(ctx, funcName, "按账号查询用户", zap.String("account", account))

	var user model.User
	err := d.db.WithContext(ctx).
		Where("username = ? OR email = ?", account, account).
		First(&user).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}
