using System.Diagnostics.Metrics;
using Microsoft.AspNetCore.Http;
using Nexus.Api.Controllers;
using Nexus.Api.Models;
using Nexus.Api.Observability;
using Xunit;

namespace Nexus.Api.Tests;

public sealed class BrowserTelemetryControllerTests
{
    [Fact]
    public void Record_AcceptsAllowlistedContentFreeMetric()
    {
        var controller = new BrowserTelemetryController();
        var result = controller.Record(new BrowserMetricRequest(
            "board_content_visible",
            314.2,
            "custom",
            "Task Board",
            "test",
            "spa",
            "live",
            null));

        Assert.Equal(StatusCodes.Status204NoContent, ResultStatusCode(result));
    }

    [Fact]
    public void Record_RejectsUnknownMetricAndInvalidValue()
    {
        var controller = new BrowserTelemetryController();

        Assert.Equal(
            StatusCodes.Status400BadRequest,
            ResultStatusCode(controller.Record(new BrowserMetricRequest(
                "task-content",
                1,
                "custom",
                "Tasks",
                "test",
                "spa",
                "live",
                null))));
        Assert.Equal(
            StatusCodes.Status400BadRequest,
            ResultStatusCode(controller.Record(new BrowserMetricRequest(
                "LCP",
                double.PositiveInfinity,
                "good",
                "Tasks",
                "test",
                "navigate",
                "unknown",
                null))));
    }

    [Fact]
    public void Record_RoutesClsToUnitlessScoreAndDurationsToMilliseconds()
    {
        var measurements = new List<(string Name, string? Unit, double Value)>();
        using var listener = new MeterListener();
        listener.InstrumentPublished = (instrument, activeListener) =>
        {
            if (instrument.Meter.Name == NexusTelemetry.SourceName &&
                instrument.Name is "nexus.browser.score" or "nexus.browser.duration")
            {
                activeListener.EnableMeasurementEvents(instrument);
            }
        };
        listener.SetMeasurementEventCallback<double>((instrument, value, _, _) =>
            measurements.Add((instrument.Name, instrument.Unit, value)));
        listener.Start();

        var controller = new BrowserTelemetryController();
        controller.Record(new BrowserMetricRequest(
            "CLS",
            0.123456,
            "good",
            "Dashboard",
            "test",
            "navigate",
            "live",
            null));
        controller.Record(new BrowserMetricRequest(
            "LCP",
            1234.5678,
            "good",
            "Dashboard",
            "test",
            "navigate",
            "live",
            null));

        Assert.Contains(
            measurements,
            item => item is ("nexus.browser.score", "1", 0.123456));
        Assert.Contains(
            measurements,
            item => item is ("nexus.browser.duration", "ms", 1234.5678));
    }

    private static int? ResultStatusCode(IResult result)
        => result is IStatusCodeHttpResult statusCodeResult
            ? statusCodeResult.StatusCode
            : null;
}
