using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Knot.Modules.Stories.Application.Abstractions;
using Knot.Modules.Stories.Application.DTOs;
using Knot.Modules.Stories.Application.Stories;
using Knot.Modules.Stories.Domain;
using Knot.Modules.Stories.Infrastructure.Database;
using Knot.Shared.Kernel;
using MediatR;
using Microsoft.EntityFrameworkCore;

namespace Knot.Modules.Stories.Application.Stories.Commands.ViewStory;

public record ViewStoryCommand(Guid UserId, Guid StoryId) : ICommand<MessageResponse>;

internal sealed class ViewStoryCommandHandler : ICommandHandler<ViewStoryCommand, MessageResponse>
{
    private readonly StoriesDbContext _context;
    private readonly Knot.Modules.Stories.Application.Abstractions.IStoryRepository _storyRepository;
    private readonly IUserRepository _userRepository;
    private readonly IStoryNotificationService _notificationService;

    public ViewStoryCommandHandler(
        StoriesDbContext context,
        Knot.Modules.Stories.Application.Abstractions.IStoryRepository storyRepository,
        IUserRepository userRepository,
        IStoryNotificationService notificationService)
    {
        _context = context;
        _storyRepository = storyRepository;
        _userRepository = userRepository;
        _notificationService = notificationService;
    }

    public async Task<Result<MessageResponse>> Handle(ViewStoryCommand request, CancellationToken cancellationToken)
    {
        try
        {
            var story = await _storyRepository.GetByIdAsync(request.StoryId, cancellationToken);

            if (story == null)
            {
                return Result.Failure<MessageResponse>(StoryErrors.StoryNotFound);
            }

            if (story.UserId == request.UserId)
            {
                return Result.Success(new MessageResponse("Owner view"));
            }

            if (!await _context.StoryViewers.AnyAsync(v => v.StoryId == request.StoryId && v.UserId == request.UserId, cancellationToken))
            {
                _context.StoryViewers.Add(StoryViewer.Create(story.Id, request.UserId));
                await _context.SaveChangesAsync(cancellationToken);

                await _storyRepository.IncrementViewsCountAsync(story.Id, cancellationToken);

                var viewer = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);

                await _notificationService.NotifyStoryViewedAsync(
                    story.Id,
                    request.UserId,
                    viewer?.Username,
                    viewer?.DisplayName,
                    viewer?.Avatar,
                    story.ViewsCount + 1,
                    story.UserId,
                    cancellationToken);
            }
            return Result.Success(new MessageResponse("Story viewed"));
        }
        catch (DbUpdateException)
        {
            return Result.Success(new MessageResponse("Story already viewed"));
        }
    }
}




