package assessment import ( "Yimaru-Backend/internal/domain" "context" "errors" "time" ) func (s *Service) GetActiveAssessmentQuestions( ctx context.Context, ) ([]domain.AssessmentQuestion, error) { questions, err := s.initialAssessmentStore.GetActiveAssessmentQuestions(ctx) if err != nil { return nil, err } // IMPORTANT: // Do NOT expose correct answers to the client for i := range questions { for j := range questions[i].Options { questions[i].Options[j].IsCorrect = false } } return questions, nil } func (s *Service) CreateAssessmentQuestion( ctx context.Context, q domain.AssessmentQuestion, ) (domain.AssessmentQuestion, error) { // Basic validation if q.Title == "" { return domain.AssessmentQuestion{}, errors.New("question title is required") } if q.QuestionType == "" { return domain.AssessmentQuestion{}, errors.New("question type is required") } if q.DifficultyLevel == "" { return domain.AssessmentQuestion{}, errors.New("difficulty level is required") } // Multiple choice / true-false must have options if q.QuestionType != string(domain.QuestionTypeShortAnswer) { if len(q.Options) < 2 { return domain.AssessmentQuestion{}, errors.New("at least two options are required") } hasCorrect := false for _, opt := range q.Options { if opt.OptionText == "" { return domain.AssessmentQuestion{}, errors.New("option text cannot be empty") } if opt.IsCorrect { hasCorrect = true } } if !hasCorrect { return domain.AssessmentQuestion{}, errors.New("at least one correct option is required") } } // Persist via repository return s.initialAssessmentStore.CreateAssessmentQuestion(ctx, q) } func (s *Service) SubmitAssessment( ctx context.Context, userID int64, responses []domain.UserAnswer, ) (domain.AssessmentAttempt, error) { if userID <= 0 { return domain.AssessmentAttempt{}, errors.New("invalid user id") } if len(responses) == 0 { return domain.AssessmentAttempt{}, errors.New("no responses submitted") } // Step 1: Validate and evaluate answers for i, ans := range responses { if ans.QuestionID == 0 { return domain.AssessmentAttempt{}, errors.New("invalid question id") } isCorrect, err := s.validateAnswer(ctx, ans) if err != nil { return domain.AssessmentAttempt{}, err } responses[i].IsCorrect = isCorrect } // Step 2: Persist assessment attempt + answers attempt, err := s.initialAssessmentStore.SaveAssessmentAttempt( ctx, userID, responses, ) if err != nil { return domain.AssessmentAttempt{}, err } // Step 3: Update user's knowledge level if err := s.userStore.UpdateUserKnowledgeLevel( ctx, userID, attempt.KnowledgeLevel, ); err != nil { return domain.AssessmentAttempt{}, err } // Step 4: Send in-app notification notification := &domain.Notification{ RecipientID: userID, Level: domain.NotificationLevelInfo, Reciever: domain.NotificationRecieverSideCustomer, IsRead: false, DeliveryStatus: domain.DeliveryStatusSent, DeliveryChannel: domain.DeliveryChannelInApp, Payload: domain.NotificationPayload{ Headline: "Knowledge Assessment Completed", Message: "Your knowledge assessment is complete. Your knowledge level is " + attempt.KnowledgeLevel + ".", Tags: []string{"assessment", "knowledge-level"}, }, Timestamp: time.Now(), Type: domain.NOTIFICATION_TYPE_KNOWLEDGE_LEVEL_UPDATE, } if err := s.notificationSvc.SendNotification(ctx, notification); err != nil { return domain.AssessmentAttempt{}, err } return attempt, nil } func (s *Service) validateAnswer( ctx context.Context, answer domain.UserAnswer, ) (bool, error) { // Multiple choice / True-False if answer.SelectedOptionID != 0 { option, err := s.initialAssessmentStore.GetOptionByID( ctx, answer.SelectedOptionID, ) if err != nil { return false, err } return option.IsCorrect, nil } // Short answer (future-proofing) if answer.ShortAnswer != "" { // Placeholder: subjective/manual evaluation // For now, mark incorrect return false, nil } return false, errors.New("invalid answer submission") } func CalculateKnowledgeLevel(score float64) string { switch { case score >= 80: return "ADVANCED" case score >= 50: return "INTERMEDIATE" default: return "BEGINNER" } }