using FluentAssertions;
using Knot.Modules.Stories.Application.Stories.Commands.DeleteStory;
using Knot.Modules.Stories.Domain;
using Knot.Shared.Kernel;
using Knot.Modules.Stories.Application.Abstractions;
using NSubstitute;
using Xunit;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Knot.Modules.Stories.UnitTests;

public class DeleteStoryCommandHandlerTests
{
    private readonly IStoryRepository _storyRepository;
    private readonly DeleteStoryCommandHandler _handler;

    public DeleteStoryCommandHandlerTests()
    {
        _storyRepository = Substitute.For<IStoryRepository>();
        _handler = new DeleteStoryCommandHandler(_storyRepository);
    }

    [Fact]
    public async Task Handle_ShouldReturnError_WhenStoryNotFound()
    {
        // Arrange
        var command = new DeleteStoryCommand(Guid.NewGuid(), Guid.NewGuid());
        _storyRepository.GetByIdAsync(command.StoryId, Arg.Any<CancellationToken>()).Returns((Story?)null);

        // Act
        var result = await _handler.Handle(command, CancellationToken.None);

        // Assert
        result.IsFailure.Should().BeTrue();
        result.Error.Should().Be(StoryErrors.StoryNotFound);
    }

    [Fact]
    public async Task Handle_ShouldReturnError_WhenUserIsNotOwner()
    {
        // Arrange
        var ownerId = Guid.NewGuid();
        var viewerId = Guid.NewGuid();
        var story = Story.Create(ownerId, StoryType.Text, null, "Content", null);
        var command = new DeleteStoryCommand(viewerId, story.Id);

        _storyRepository.GetByIdAsync(command.StoryId, Arg.Any<CancellationToken>()).Returns(story);

        // Act
        var result = await _handler.Handle(command, CancellationToken.None);

        // Assert
        result.IsFailure.Should().BeTrue();
        result.Error.Should().Be(StoryErrors.Unauthorized);
    }

    [Fact]
    public async Task Handle_ShouldSucceed_WhenOwnerDeletes()
    {
        // Arrange
        var ownerId = Guid.NewGuid();
        var story = Story.Create(ownerId, StoryType.Text, null, "Content", null);
        var command = new DeleteStoryCommand(ownerId, story.Id);

        _storyRepository.GetByIdAsync(command.StoryId, Arg.Any<CancellationToken>()).Returns(story);

        // Act
        var result = await _handler.Handle(command, CancellationToken.None);

        // Assert
        result.IsSuccess.Should().BeTrue();
        await _storyRepository.Received(1).DeleteAsync(story, Arg.Any<CancellationToken>());
    }
}
