using FluentAssertions;
using Moq;
using ColaFlow.Modules.ProjectManagement.Application.Queries.GetTaskById;
using ColaFlow.Modules.ProjectManagement.Application.Common.Interfaces;
using ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate;
using ColaFlow.Modules.ProjectManagement.Domain.Repositories;
using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
using ColaFlow.Modules.ProjectManagement.Domain.Exceptions;

namespace ColaFlow.Application.Tests.Queries.GetTaskById;

public class GetTaskByIdQueryHandlerTests
{
    private readonly Mock<IProjectRepository> _projectRepositoryMock;
    private readonly Mock<ITenantContext> _tenantContextMock;
    private readonly GetTaskByIdQueryHandler _handler;
    private readonly Guid _tenantId;

    public GetTaskByIdQueryHandlerTests()
    {
        _projectRepositoryMock = new Mock<IProjectRepository>();
        _tenantContextMock = new Mock<ITenantContext>();
        _tenantId = Guid.NewGuid();

        // Setup default tenant context
        _tenantContextMock.Setup(x => x.GetCurrentTenantId()).Returns(_tenantId);

        _handler = new GetTaskByIdQueryHandler(_projectRepositoryMock.Object, _tenantContextMock.Object);
    }

    [Fact]
    public async Task Should_Return_Task_Details()
    {
        // Arrange
        var userId = UserId.Create();
        var project = Project.Create(TenantId.Create(_tenantId), "Test Project", "Description", "TST", userId);
        var epic = project.CreateEpic("Test Epic", "Epic Description", userId);
        var story = epic.CreateStory("Test Story", "Story Description", TaskPriority.Medium, userId);
        var task = story.CreateTask("Test Task", "Task Description", TaskPriority.High, userId);

        _projectRepositoryMock
            .Setup(x => x.GetTaskByIdReadOnlyAsync(task.Id, It.IsAny<CancellationToken>()))
            .ReturnsAsync(task);

        var query = new GetTaskByIdQuery(task.Id.Value);

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

        // Assert
        result.Should().NotBeNull();
        result.Id.Should().Be(task.Id.Value);
        result.Title.Should().Be("Test Task");
        result.Description.Should().Be("Task Description");
        result.StoryId.Should().Be(story.Id.Value);
        result.Status.Should().Be("To Do");
        result.Priority.Should().Be("High");
    }

    [Fact]
    public async Task Should_Fail_When_Task_Not_Found()
    {
        // Arrange
        var taskId = TaskId.Create();
        _projectRepositoryMock
            .Setup(x => x.GetTaskByIdReadOnlyAsync(taskId, It.IsAny<CancellationToken>()))
            .ReturnsAsync((WorkTask?)null);

        var query = new GetTaskByIdQuery(taskId.Value);

        // Act
        Func<Task> act = async () => await _handler.Handle(query, CancellationToken.None);

        // Assert
        await act.Should().ThrowAsync<NotFoundException>()
            .WithMessage("*Task*");
    }
}
