using System.Net;
using System.Net.Http;
using Metin2Launcher.Telemetry;
using Xunit;

namespace Metin2Launcher.Tests;

public class ClientAppliedReporterTests
{
    [Fact]
    public void Disabled_when_template_is_empty()
    {
        using var http = new HttpClient();
        var r = new ClientAppliedReporter(http, "");
        Assert.False(r.IsEnabled);
    }

    [Fact]
    public void Disabled_when_template_is_null()
    {
        using var http = new HttpClient();
        var r = new ClientAppliedReporter(http, null);
        Assert.False(r.IsEnabled);
    }

    [Fact]
    public void Disabled_when_template_is_whitespace()
    {
        using var http = new HttpClient();
        var r = new ClientAppliedReporter(http, "   ");
        Assert.False(r.IsEnabled);
    }

    [Fact]
    public async Task ReportAsync_noop_when_disabled()
    {
        using var http = new HttpClient();
        var r = new ClientAppliedReporter(http, "");
        var ok = await r.ReportAsync("m2pack", "v1", CancellationToken.None);
        Assert.False(ok);
    }

    [Fact]
    public void Expand_substitutes_placeholders()
    {
        var s = ClientAppliedReporter.Expand("https://x/{format}/{version}", "m2pack", "2026.04.14-1");
        Assert.Equal("https://x/m2pack/2026.04.14-1", s);
    }

    [Fact]
    public void Expand_uri_escapes_values()
    {
        var s = ClientAppliedReporter.Expand("https://x/{version}", "m2pack", "v 1+beta");
        Assert.Contains("v%201%2Bbeta", s);
    }

    [Fact]
    public void Expand_leaves_unknown_placeholders()
    {
        var s = ClientAppliedReporter.Expand("https://x/{other}", "m2pack", "v1");
        Assert.Equal("https://x/{other}", s);
    }

    [Fact]
    public async Task ReportAsync_posts_json_on_success()
    {
        using var listener = new TestHttpListener();
        var url = listener.Start();
        listener.RespondWith(HttpStatusCode.OK);

        using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
        var r = new ClientAppliedReporter(http, url + "?format={format}&version={version}");
        var ok = await r.ReportAsync("m2pack", "2026.04.14-1", CancellationToken.None);

        Assert.True(ok);
        var req = listener.LastRequest!;
        Assert.Equal("POST", req.Method);
        Assert.Contains("format=m2pack", req.RawUrl);
        Assert.Contains("\"Format\":\"m2pack\"", req.Body);
        Assert.Contains("\"Version\":\"2026.04.14-1\"", req.Body);
    }

    [Fact]
    public async Task ReportAsync_returns_false_on_500()
    {
        using var listener = new TestHttpListener();
        var url = listener.Start();
        listener.RespondWith(HttpStatusCode.InternalServerError);

        using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
        var r = new ClientAppliedReporter(http, url);
        var ok = await r.ReportAsync("m2pack", "v1", CancellationToken.None);
        Assert.False(ok);
    }

    [Fact]
    public async Task ReportAsync_swallows_connection_refused()
    {
        using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(2) };
        // pick a port unlikely to be listening
        var r = new ClientAppliedReporter(http, "http://127.0.0.1:1/");
        var ok = await r.ReportAsync("m2pack", "v1", CancellationToken.None);
        Assert.False(ok);
    }

    [Fact]
    public async Task ReportAsync_times_out_after_five_seconds()
    {
        using var listener = new TestHttpListener();
        var url = listener.Start();
        listener.RespondAfter(TimeSpan.FromSeconds(10), HttpStatusCode.OK);

        using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
        var r = new ClientAppliedReporter(http, url);

        var sw = System.Diagnostics.Stopwatch.StartNew();
        var ok = await r.ReportAsync("m2pack", "v1", CancellationToken.None);
        sw.Stop();

        Assert.False(ok);
        // reporter caps at 5s internally — allow slack for CI schedulers
        Assert.InRange(sw.Elapsed.TotalSeconds, 3.0, 9.0);
    }
}
