using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Deployment;
using ZB.MOM.WW.ScadaBridge.ManagementService;

namespace ZB.MOM.WW.ScadaBridge.ManagementService.Tests;

/// <summary>
/// Unit tests for the pure decision resolver behind the token-gated internal
/// deployment-config fetch endpoint (<see cref="DeploymentConfigEndpoints.Resolve"/>).
///
/// <para>
/// This endpoint is machine-to-machine: a site presents a per-deployment fetch
/// token in the <c>X-Deployment-Token</c> header and the token is the entire
/// security boundary. The resolver is extracted so the security-critical
/// decision logic is unit-testable without standing up a web host. The mapping
/// from the resolver result to the documented HTTP status codes is:
/// <list type="bullet">
///   <item>unknown / superseded (null row) → 404 NotFound</item>
///   <item>expired row → 404 NotFound (does not leak existence to a wrong token)</item>
///   <item>missing / wrong token → 401 Unauthorized</item>
///   <item>valid row + correct token + not expired → 200 with the staged JSON</item>
/// </list>
/// </para>
/// </summary>
public class DeploymentConfigEndpointsTests
{
    private const string ValidToken = "test-deployment-token-abc123";
    private const string ConfigJson = "{\"instanceId\":42,\"attributes\":[]}";

    private static readonly DateTimeOffset Now = new(2026, 6, 26, 12, 0, 0, TimeSpan.Zero);

    private static PendingDeployment Row(string token = ValidToken, DateTimeOffset? expiresAtUtc = null) =>
        new(
            deploymentId: "deploy-1",
            instanceId: 42,
            revisionHash: "hash-1",
            configurationJson: ConfigJson,
            token: token,
            createdAtUtc: Now.AddMinutes(-1),
            expiresAtUtc: expiresAtUtc ?? Now.AddMinutes(5));

    private static int? StatusOf(IResult result) => (result as IStatusCodeHttpResult)?.StatusCode;

    [Fact]
    public void Resolve_NullRow_ReturnsNotFound()
    {
        var result = DeploymentConfigEndpoints.Resolve(row: null, token: ValidToken, nowUtc: Now);

        Assert.IsType<NotFound>(result);
        Assert.Equal(StatusCodes.Status404NotFound, StatusOf(result));
    }

    [Fact]
    public void Resolve_ExpiredRow_WithCorrectToken_ReturnsNotFound()
    {
        // Expired exactly at now: ExpiresAtUtc <= now is the boundary that purges.
        var row = Row(expiresAtUtc: Now);

        var result = DeploymentConfigEndpoints.Resolve(row, token: ValidToken, nowUtc: Now);

        Assert.IsType<NotFound>(result);
        Assert.Equal(StatusCodes.Status404NotFound, StatusOf(result));
    }

    [Fact]
    public void Resolve_ExpiredRowInThePast_WithCorrectToken_ReturnsNotFound()
    {
        var row = Row(expiresAtUtc: Now.AddSeconds(-1));

        var result = DeploymentConfigEndpoints.Resolve(row, token: ValidToken, nowUtc: Now);

        Assert.IsType<NotFound>(result);
        Assert.Equal(StatusCodes.Status404NotFound, StatusOf(result));
    }

    [Fact]
    public void Resolve_ValidRow_WrongToken_ReturnsUnauthorized()
    {
        var row = Row();

        var result = DeploymentConfigEndpoints.Resolve(row, token: "wrong-token", nowUtc: Now);

        Assert.IsType<UnauthorizedHttpResult>(result);
        Assert.Equal(StatusCodes.Status401Unauthorized, StatusOf(result));
    }

    [Fact]
    public void Resolve_ValidRow_EmptyToken_ReturnsUnauthorized()
    {
        var row = Row();

        var result = DeploymentConfigEndpoints.Resolve(row, token: string.Empty, nowUtc: Now);

        Assert.IsType<UnauthorizedHttpResult>(result);
        Assert.Equal(StatusCodes.Status401Unauthorized, StatusOf(result));
    }

    [Fact]
    public void Resolve_ValidRow_NullToken_ReturnsUnauthorized()
    {
        var row = Row();

        var result = DeploymentConfigEndpoints.Resolve(row, token: null!, nowUtc: Now);

        Assert.IsType<UnauthorizedHttpResult>(result);
        Assert.Equal(StatusCodes.Status401Unauthorized, StatusOf(result));
    }

    [Fact]
    public void Resolve_ValidRow_CorrectToken_NotExpired_ReturnsConfigJson()
    {
        var row = Row();

        var result = DeploymentConfigEndpoints.Resolve(row, token: ValidToken, nowUtc: Now);

        var content = Assert.IsType<ContentHttpResult>(result);
        Assert.Equal(ConfigJson, content.ResponseContent);
        Assert.Equal("application/json", content.ContentType);
    }
}
