package repository import ( "errors" "time" "github.com/topfans/backend/pkg/logger" "github.com/topfans/backend/services/taskService/model" "go.uber.org/zap" "gorm.io/gorm" ) type OnboardingRepository interface { GetOnboardingStatus(userID int64, starID int64) (*model.UserOnboardingStatus, error) GetOrCreateOnboardingStatus(userID int64, starID int64) (*model.UserOnboardingStatus, error) UpdateOnboardingStatus(status *model.UserOnboardingStatus) error UpdateOnboardingProgress(progress *model.UserOnboardingProgress) error GetUserOnboardingProgress(userID int64, taskKey string) (*model.UserOnboardingProgress, error) GetOrCreateOnboardingProgress(userID int64, taskKey string) (*model.UserOnboardingProgress, error) ListActiveStageConfigs() ([]*model.OnboardingStageConfig, error) ListUserOnboardingProgressByUser(userID int64) ([]*model.UserOnboardingProgress, error) GetStageConfig(stage int64) (*model.OnboardingStageConfig, error) } type onboardingRepository struct { db *gorm.DB } func NewOnboardingRepository(db *gorm.DB) OnboardingRepository { return &onboardingRepository{db: db} } func (r *onboardingRepository) GetOnboardingStatus(userID int64, starID int64) (*model.UserOnboardingStatus, error) { var status model.UserOnboardingStatus err := r.db.Where("user_id = ? AND star_id = ?", userID, starID).First(&status).Error if err != nil { return nil, err } return &status, nil } func (r *onboardingRepository) GetOrCreateOnboardingStatus(userID int64, starID int64) (*model.UserOnboardingStatus, error) { var status model.UserOnboardingStatus err := r.db.Where("user_id = ? AND star_id = ?", userID, starID).First(&status).Error if err == nil { return &status, nil } if !errors.Is(err, gorm.ErrRecordNotFound) { logger.Logger.Error("Failed to GetOrCreateOnboardingStatus", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Error(err)) return nil, err } now := time.Now().Unix() status = model.UserOnboardingStatus{ UserID: userID, StarID: starID, CurrentStage: 0, Status: "pending", CreatedAt: now, UpdatedAt: now, } if err := r.db.Create(&status).Error; err != nil { logger.Logger.Error("Failed to Create OnboardingStatus", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Error(err)) return nil, err } return &status, nil } func (r *onboardingRepository) UpdateOnboardingStatus(status *model.UserOnboardingStatus) error { status.UpdatedAt = time.Now().Unix() if err := r.db.Save(status).Error; err != nil { logger.Logger.Error("Failed to UpdateOnboardingStatus", zap.Int64("user_id", status.UserID), zap.Error(err)) return err } return nil } func (r *onboardingRepository) UpdateOnboardingProgress(progress *model.UserOnboardingProgress) error { progress.UpdatedAt = time.Now().Unix() if err := r.db.Save(progress).Error; err != nil { logger.Logger.Error("Failed to UpdateOnboardingProgress", zap.Int64("user_id", progress.UserID), zap.String("task_key", progress.TaskKey), zap.Error(err)) return err } return nil } func (r *onboardingRepository) GetUserOnboardingProgress(userID int64, taskKey string) (*model.UserOnboardingProgress, error) { var progress model.UserOnboardingProgress err := r.db.Where("user_id = ? AND task_key = ?", userID, taskKey).First(&progress).Error if err != nil { return nil, err } return &progress, nil } func (r *onboardingRepository) GetOrCreateOnboardingProgress(userID int64, taskKey string) (*model.UserOnboardingProgress, error) { var progress model.UserOnboardingProgress err := r.db.Where("user_id = ? AND task_key = ?", userID, taskKey).First(&progress).Error if err == nil { return &progress, nil } if !errors.Is(err, gorm.ErrRecordNotFound) { logger.Logger.Error("Failed to GetOrCreateOnboardingProgress", zap.Int64("user_id", userID), zap.String("task_key", taskKey), zap.Error(err)) return nil, err } now := time.Now().Unix() progress = model.UserOnboardingProgress{ UserID: userID, TaskKey: taskKey, Status: "pending", CreatedAt: now, UpdatedAt: now, } if err := r.db.Create(&progress).Error; err != nil { logger.Logger.Error("Failed to Create OnboardingProgress", zap.Int64("user_id", userID), zap.String("task_key", taskKey), zap.Error(err)) return nil, err } return &progress, nil } func (r *onboardingRepository) ListActiveStageConfigs() ([]*model.OnboardingStageConfig, error) { var configs []*model.OnboardingStageConfig err := r.db.Where("is_active = ?", true).Order("sort_order ASC").Find(&configs).Error if err != nil { logger.Logger.Error("Failed to ListActiveStageConfigs", zap.Error(err)) return nil, err } return configs, nil } func (r *onboardingRepository) ListUserOnboardingProgressByUser(userID int64) ([]*model.UserOnboardingProgress, error) { var progressList []*model.UserOnboardingProgress err := r.db.Where("user_id = ?", userID).Find(&progressList).Error if err != nil { logger.Logger.Error("Failed to ListUserOnboardingProgressByUser", zap.Int64("user_id", userID), zap.Error(err)) return nil, err } return progressList, nil } func (r *onboardingRepository) GetStageConfig(stage int64) (*model.OnboardingStageConfig, error) { var config model.OnboardingStageConfig err := r.db.Where("stage = ? AND is_active = ?", stage, true).First(&config).Error if err != nil { return nil, err } return &config, nil }