using System.Reflection;
using ErsatzTV.Application.Health;
using ErsatzTV.Controllers.Api;
using ErsatzTV.Core.Api.Health;
using MediatR;
using Microsoft.AspNetCore.Mvc.Routing;
using NSubstitute;
using NUnit.Framework;
using Shouldly;

namespace ErsatzTV.Tests.Controllers;

[TestFixture]
public class HealthControllerTests
{
    private IMediator _mediator = null!;
    private HealthController _controller = null!;

    [SetUp]
    public void SetUp()
    {
        _mediator = Substitute.For<IMediator>();
        _controller = new HealthController(_mediator);
    }

    [Test]
    public void Controller_Should_Expose_Idiomatic_Rest_Route()
    {
        MethodInfo action = typeof(HealthController).GetMethod(nameof(HealthController.GetAll))
            ?? throw new AssertionException("Missing action GetAll");

        HttpMethodAttribute attribute = action.GetCustomAttributes<HttpMethodAttribute>(inherit: true).Single();
        attribute.HttpMethods.ShouldContain("GET");
        attribute.Template.ShouldBe("/api/v1/health");
        attribute.Name.ShouldBe("GetHealthChecks");
    }

    [Test]
    public async Task GetAll_Should_Return_Results_From_Mediator()
    {
        var expected = new List<HealthCheckResponseModel>
        {
            new("Check One", "pass", "all good", null, null, null),
            new(
                "Check Two",
                "fail",
                "broken",
                "broken",
                "https://example.com",
                new HealthCheckRemediationResponseModel("ExternalDoc", "https://example.com"))
        };

        _mediator.Send(Arg.Any<GetAllHealthCheckResultsForApi>(), Arg.Any<CancellationToken>())
            .Returns(expected);

        List<HealthCheckResponseModel> result = await _controller.GetAll(false, CancellationToken.None);

        result.ShouldBe(expected);
    }

    [Test]
    public async Task GetAll_Should_Return_Empty_List_When_None_Exist()
    {
        _mediator.Send(Arg.Any<GetAllHealthCheckResultsForApi>(), Arg.Any<CancellationToken>())
            .Returns([]);

        List<HealthCheckResponseModel> result = await _controller.GetAll(false, CancellationToken.None);

        result.ShouldBeEmpty();
    }

    [Test]
    public async Task GetAll_Should_Forward_Refresh_Flag_To_Query()
    {
        _mediator.Send(Arg.Any<GetAllHealthCheckResultsForApi>(), Arg.Any<CancellationToken>())
            .Returns([]);

        await _controller.GetAll(true, CancellationToken.None);

        await _mediator.Received(1).Send(
            Arg.Is<GetAllHealthCheckResultsForApi>(q => q.Refresh),
            Arg.Any<CancellationToken>());
    }
}
