using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using ROLAC.API.Data;
using ROLAC.API.Data.Interceptors;
using ROLAC.API.Entities;
using ROLAC.API.Services.Ai;
using ROLAC.API.Services.Logging;
using Xunit;

namespace ROLAC.API.Tests.Services;

public class ExpenseAiServiceFactoryTests
{
    // ChurchProfile is auditable, so the InMemory store rejects saves unless the
    // required CreatedBy/UpdatedBy fields are populated. Wire the same audit
    // interceptor the app uses so seeded entities save cleanly.
    private static AppDbContext NewDb()
    {
        var httpContext = new DefaultHttpContext
        {
            User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "test-user") })),
        };
        var httpContextAccessor = new Mock<IHttpContextAccessor>();
        httpContextAccessor.Setup(accessor => accessor.HttpContext).Returns(httpContext);
        return new AppDbContext(new DbContextOptionsBuilder<AppDbContext>()
            .UseInMemoryDatabase(Guid.NewGuid().ToString())
            .ConfigureWarnings(warnings => warnings.Ignore(InMemoryEventId.TransactionIgnoredWarning))
            .AddInterceptors(new AuditSaveChangesInterceptor(new CurrentUserAccessor(httpContextAccessor.Object)))
            .Options);
    }

    private static ExpenseAiServiceFactory Build(AppDbContext db)
    {
        var cfg = new ChurchAiConfigProvider(db);
        var claude = new ClaudeExpenseAiService(
            new HttpClient(), cfg, db, NullLogger<ClaudeExpenseAiService>.Instance);
        var gemini = new GeminiExpenseAiService(
            new HttpClient(), cfg, db, NullLogger<GeminiExpenseAiService>.Instance);
        return new ExpenseAiServiceFactory(cfg, claude, gemini);
    }

    [Fact]
    public async Task Resolves_Claude_by_default()
    {
        using var db = NewDb();
        db.ChurchProfiles.Add(new ChurchProfile { Name = "C", AiProvider = "Claude" });
        await db.SaveChangesAsync();

        var svc = await Build(db).ResolveAsync();

        Assert.IsType<ClaudeExpenseAiService>(svc);
    }

    [Fact]
    public async Task Resolves_Gemini_when_selected()
    {
        using var db = NewDb();
        db.ChurchProfiles.Add(new ChurchProfile { Name = "C", AiProvider = "Gemini" });
        await db.SaveChangesAsync();

        var svc = await Build(db).ResolveAsync();

        Assert.IsType<GeminiExpenseAiService>(svc);
    }
}
