using System.Text.Json;
using ColaFlow.Modules.Mcp.Application.Resources;
using ColaFlow.Modules.Mcp.Contracts.Resources;
using ColaFlow.Modules.ProjectManagement.Application.Common.Interfaces;
using ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate;
using ColaFlow.Modules.ProjectManagement.Domain.Enums;
using ColaFlow.Modules.ProjectManagement.Domain.Repositories;
using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using NSubstitute;

namespace ColaFlow.Modules.Mcp.Tests.Resources;

/// <summary>
/// Unit tests for ProjectsListResource
/// </summary>
public class ProjectsListResourceTests
{
    private readonly IProjectRepository _projectRepository;
    private readonly ITenantContext _tenantContext;
    private readonly ILogger<ProjectsListResource> _logger;
    private readonly ProjectsListResource _sut;
    private readonly Guid _tenantId = Guid.NewGuid();

    public ProjectsListResourceTests()
    {
        _projectRepository = Substitute.For<IProjectRepository>();
        _tenantContext = Substitute.For<ITenantContext>();
        _logger = Substitute.For<ILogger<ProjectsListResource>>();

        _tenantContext.GetCurrentTenantId().Returns(_tenantId);

        _sut = new ProjectsListResource(_projectRepository, _tenantContext, _logger);
    }

    [Fact]
    public void Uri_ReturnsCorrectValue()
    {
        // Assert
        _sut.Uri.Should().Be("colaflow://projects.list");
    }

    [Fact]
    public void Name_ReturnsCorrectValue()
    {
        // Assert
        _sut.Name.Should().Be("Projects List");
    }

    [Fact]
    public void MimeType_ReturnsApplicationJson()
    {
        // Assert
        _sut.MimeType.Should().Be("application/json");
    }

    [Fact]
    public async Task GetContentAsync_WithNoProjects_ReturnsEmptyList()
    {
        // Arrange
        _projectRepository.GetAllProjectsReadOnlyAsync(Arg.Any<CancellationToken>())
            .Returns(new List<Project>());

        var request = new McpResourceRequest { Uri = "colaflow://projects.list" };

        // Act
        var result = await _sut.GetContentAsync(request, CancellationToken.None);

        // Assert
        result.Should().NotBeNull();
        result.Uri.Should().Be("colaflow://projects.list");
        result.MimeType.Should().Be("application/json");

        var data = JsonSerializer.Deserialize<JsonElement>(result.Text);
        data.GetProperty("projects").GetArrayLength().Should().Be(0);
        data.GetProperty("total").GetInt32().Should().Be(0);
    }

    [Fact]
    public async Task GetContentAsync_WithProjects_ReturnsProjectsList()
    {
        // Arrange
        var project1 = Project.Create(
            ColaFlow.Modules.ProjectManagement.Domain.ValueObjects.TenantId.From(_tenantId),
            "Project Alpha",
            "First project",
            "ALPHA",
            UserId.Create());

        var project2 = Project.Create(
            ColaFlow.Modules.ProjectManagement.Domain.ValueObjects.TenantId.From(_tenantId),
            "Project Beta",
            "Second project",
            "BETA",
            UserId.Create());

        _projectRepository.GetAllProjectsReadOnlyAsync(Arg.Any<CancellationToken>())
            .Returns(new List<Project> { project1, project2 });

        var request = new McpResourceRequest { Uri = "colaflow://projects.list" };

        // Act
        var result = await _sut.GetContentAsync(request, CancellationToken.None);

        // Assert
        result.Should().NotBeNull();
        var data = JsonSerializer.Deserialize<JsonElement>(result.Text);

        data.GetProperty("total").GetInt32().Should().Be(2);

        var projects = data.GetProperty("projects");
        projects.GetArrayLength().Should().Be(2);

        var firstProject = projects[0];
        firstProject.GetProperty("name").GetString().Should().Be("Project Alpha");
        firstProject.GetProperty("key").GetString().Should().Be("ALPHA");
        firstProject.GetProperty("status").GetString().Should().Be(ProjectStatus.Active.ToString());
    }

    [Fact]
    public async Task GetContentAsync_CallsTenantContext()
    {
        // Arrange
        _projectRepository.GetAllProjectsReadOnlyAsync(Arg.Any<CancellationToken>())
            .Returns(new List<Project>());

        var request = new McpResourceRequest { Uri = "colaflow://projects.list" };

        // Act
        await _sut.GetContentAsync(request, CancellationToken.None);

        // Assert
        _tenantContext.Received(1).GetCurrentTenantId();
    }

    [Fact]
    public async Task GetContentAsync_CallsRepository()
    {
        // Arrange
        _projectRepository.GetAllProjectsReadOnlyAsync(Arg.Any<CancellationToken>())
            .Returns(new List<Project>());

        var request = new McpResourceRequest { Uri = "colaflow://projects.list" };

        // Act
        await _sut.GetContentAsync(request, CancellationToken.None);

        // Assert
        await _projectRepository.Received(1).GetAllProjectsReadOnlyAsync(Arg.Any<CancellationToken>());
    }
}
