using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Moq;
using ROLAC.API.Data;
using ROLAC.API.Data.Interceptors;
using ROLAC.API.Services;
using Xunit;

namespace ROLAC.API.Tests.Services;

public class MealAttendanceServiceTests
{
    // MealAttendance is auditable, so the InMemory provider requires CreatedBy/UpdatedBy
    // to be set before insert. Wire in the AuditSaveChangesInterceptor (as the other
    // service tests do) so those columns are stamped automatically on SaveChanges.
    private static AppDbContext BuildDb()
    {
        var claims = new[] { new Claim(ClaimTypes.NameIdentifier, "test-user") };
        var ctx    = new DefaultHttpContext { User = new(new ClaimsIdentity(claims)) };
        var mock   = new Mock<IHttpContextAccessor>();
        mock.Setup(x => x.HttpContext).Returns(ctx);
        return new AppDbContext(new DbContextOptionsBuilder<AppDbContext>()
            .UseInMemoryDatabase(Guid.NewGuid().ToString())
            .AddInterceptors(new AuditSaveChangesInterceptor(
                new ROLAC.API.Services.Logging.CurrentUserAccessor(mock.Object))).Options);
    }

    [Fact]
    public async Task SetCountsAsync_CreatesRowWhenMissing_AndReturnsTotals()
    {
        using var db = BuildDb();
        var svc = new MealAttendanceService(db);
        var date = new DateOnly(2026, 5, 31);

        var result = await svc.SetCountsAsync(date, adult: 40, youth: 12, kid: 8);

        Assert.Equal("2026-05-31", result.Date);
        Assert.Equal(40, result.Adult);
        Assert.Equal(12, result.Youth);
        Assert.Equal(8, result.Kid);
        Assert.Single(db.MealAttendances.Where(a => a.AttendanceDate == date));
    }

    [Fact]
    public async Task SetCountsAsync_OverwritesExistingRow_AndClampsNegativesToZero()
    {
        using var db = BuildDb();
        var svc = new MealAttendanceService(db);
        var date = new DateOnly(2026, 5, 31);
        await svc.SetCountsAsync(date, 40, 12, 8);

        var result = await svc.SetCountsAsync(date, adult: 50, youth: -3, kid: 0);

        Assert.Equal(50, result.Adult);
        Assert.Equal(0,  result.Youth);   // negative clamped to zero
        Assert.Equal(0,  result.Kid);
        Assert.Single(db.MealAttendances.Where(a => a.AttendanceDate == date)); // still one row
    }
}
