using System.Threading;
using System.Threading.Tasks;
using GermanApp.Application.DTOs;
using GermanApp.Domain.Entities;
using GermanApp.Domain.Interfaces;
using Microsoft.Extensions.Logging;
namespace GermanApp.Application.Services;
///
/// Application service for managing story segment unlocking.
/// This service is called when a user completes a lesson to unlock the next story segment.
/// This is part of the Application layer.
///
public class StoryUnlockService
{
private readonly StoryService _storyService;
private readonly IUserProgressRepository _userProgressRepository;
private readonly ILessonRepository _lessonRepository;
private readonly ILogger _logger;
///
/// Creates a new StoryUnlockService.
///
/// Service for story segment operations
/// Repository for user progress
/// Repository for lessons
/// Logger for service operations
public StoryUnlockService(
StoryService storyService,
IUserProgressRepository userProgressRepository,
ILessonRepository lessonRepository,
ILogger logger)
{
_storyService = storyService;
_userProgressRepository = userProgressRepository;
_lessonRepository = lessonRepository;
_logger = logger;
}
///
/// Called when a user completes a lesson.
/// Checks if the user should unlock a new story segment and does so.
///
/// The user ID
/// The lesson ID that was completed
/// Cancellation token
/// True if a new segment was unlocked, false otherwise
public virtual async Task HandleLessonCompletionAsync(
int userId,
int lessonId,
CancellationToken cancellationToken = default)
{
_logger.LogInformation(
"Handling lesson completion for user {UserId}, lesson {LessonId}",
userId, lessonId);
// Get the lesson to find its level and order
var lesson = await _lessonRepository.GetByIdAsync(lessonId, cancellationToken);
if (lesson == null)
{
_logger.LogWarning("Lesson not found: {LessonId}", lessonId);
return false;
}
// Check if this lesson completion qualifies for unlocking a story segment
// We need to check if the user has actually completed this lesson
var isCompleted = await _userProgressRepository.HasUserCompletedLessonAsync(
userId, lessonId, cancellationToken);
if (!isCompleted)
{
_logger.LogInformation(
"Lesson {LessonId} not marked as completed for user {UserId}",
lessonId, userId);
return false;
}
// Get the next story segment to unlock
var nextSegment = await _storyService.GetNextSegmentToUnlockAsync(
lesson.LevelId,
lesson.Order,
cancellationToken);
if (nextSegment == null)
{
_logger.LogInformation(
"No story segment to unlock for user {UserId} after lesson {LessonId}",
userId, lessonId);
return false;
}
// Check if user already has this segment unlocked
var alreadyUnlocked = await _storyService.IsSegmentUnlockedAsync(
userId, nextSegment.Id, cancellationToken);
if (alreadyUnlocked)
{
_logger.LogInformation(
"Segment {SegmentId} already unlocked for user {UserId}",
nextSegment.Id, userId);
return false;
}
// Unlock the segment
var unlockedSegment = await _storyService.UnlockNextSegmentAsync(
userId,
lesson.LevelId,
lesson.Order,
cancellationToken);
if (unlockedSegment != null)
{
_logger.LogInformation(
"Unlocked story segment {SegmentId} for user {UserId} after completing lesson {LessonId}",
unlockedSegment.Id, userId, lessonId);
return true;
}
return false;
}
///
/// Checks if a user has unlocked a specific story segment.
///
/// The user ID
/// The segment ID
/// Cancellation token
/// True if the segment is unlocked
public virtual async Task IsSegmentUnlockedAsync(
int userId,
int segmentId,
CancellationToken cancellationToken = default)
{
return await _storyService.IsSegmentUnlockedAsync(userId, segmentId, cancellationToken);
}
///
/// Checks if a user has completed (read/listened to) a specific story segment.
///
/// The user ID
/// The segment ID
/// Cancellation token
/// True if the segment is completed
public virtual async Task IsSegmentCompletedAsync(
int userId,
int segmentId,
CancellationToken cancellationToken = default)
{
return await _storyService.IsSegmentCompletedAsync(userId, segmentId, cancellationToken);
}
///
/// Marks a story segment as completed for a user.
///
/// The user ID
/// The segment ID
/// Cancellation token
/// True if the segment was marked as completed
public virtual async Task MarkSegmentAsCompletedAsync(
int userId,
int segmentId,
CancellationToken cancellationToken = default)
{
return await _storyService.MarkSegmentAsCompletedAsync(userId, segmentId, cancellationToken);
}
///
/// Gets a user's story progress for a level.
///
/// The user ID
/// The level ID
/// Cancellation token
/// Story progress DTO
public virtual async Task GetUserProgressAsync(
int userId,
int levelId,
CancellationToken cancellationToken = default)
{
return await _storyService.GetUserProgressAsync(userId, levelId, cancellationToken);
}
}