using System.Net;
using System.Text.Json;
using ROLAC.API.Services.Notifications;
using Xunit;

namespace ROLAC.API.Tests.Services.Notifications;

public class LineMessageChannelTests
{
    // Stub settings provider returning fixed SMTP/Line values for the channel under test.
    private sealed class StubSettings : INotificationSettingsService
    {
        public SmtpOptions GetSmtp() => new();
        public LineOptions GetLine() => new() { ChannelAccessToken = "tok", ChannelSecret = "sec" };
        public WebPushOptions GetWebPush() => new();
        public void Reload() { }
    }

    // Captures the outgoing request and returns a canned response.
    private sealed class CapturingHandler : HttpMessageHandler
    {
        public HttpRequestMessage? LastRequest { get; private set; }
        public string? LastBody { get; private set; }
        public HttpStatusCode StatusCode { get; set; } = HttpStatusCode.OK;
        public string ResponseBody { get; set; } = "{}";

        protected override async Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request, CancellationToken cancellationToken)
        {
            LastRequest = request;
            LastBody = request.Content is null ? null : await request.Content.ReadAsStringAsync(cancellationToken);
            return new HttpResponseMessage(StatusCode) { Content = new StringContent(ResponseBody) };
        }
    }

    private static LineMessageChannel BuildChannel(CapturingHandler handler)
    {
        var http = new HttpClient(handler);
        return new LineMessageChannel(http, new StubSettings());
    }

    [Fact]
    public async Task PushToUserAsync_PostsTextMessage_WithBearerToken()
    {
        var handler = new CapturingHandler();
        var channel = BuildChannel(handler);

        var result = await channel.PushToUserAsync("U123", "hello");

        Assert.True(result.Success);
        Assert.Equal("https://api.line.me/v2/bot/message/push", handler.LastRequest!.RequestUri!.ToString());
        Assert.Equal("Bearer", handler.LastRequest.Headers.Authorization!.Scheme);
        Assert.Equal("tok", handler.LastRequest.Headers.Authorization.Parameter);

        using var doc = JsonDocument.Parse(handler.LastBody!);
        Assert.Equal("U123", doc.RootElement.GetProperty("to").GetString());
        Assert.Equal("hello", doc.RootElement.GetProperty("messages")[0].GetProperty("text").GetString());
    }

    [Fact]
    public async Task ReplyAsync_PostsToReplyEndpoint_WithReplyToken()
    {
        var handler = new CapturingHandler();
        var channel = BuildChannel(handler);

        await channel.ReplyAsync("RTOKEN", "hi back");

        Assert.Equal("https://api.line.me/v2/bot/message/reply", handler.LastRequest!.RequestUri!.ToString());
        using var doc = JsonDocument.Parse(handler.LastBody!);
        Assert.Equal("RTOKEN", doc.RootElement.GetProperty("replyToken").GetString());
    }

    [Fact]
    public async Task PushToUserAsync_ReturnsFailure_OnNonSuccessStatus()
    {
        var handler = new CapturingHandler { StatusCode = HttpStatusCode.TooManyRequests, ResponseBody = "quota" };
        var channel = BuildChannel(handler);

        var result = await channel.PushToUserAsync("U123", "hello");

        Assert.False(result.Success);
        Assert.Contains("429", result.Error);
    }
}
