using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging.Abstractions;
using NSubstitute;
using UniVerse.Application.Interfaces;
using UniVerse.Domain.Entities;
using UniVerse.Domain.Enums;
using UniVerse.Infrastructure.Data;
using UniVerse.Infrastructure.Services;
using Xunit;

namespace UniVerse.Api.Tests.Reviews;

public class LlmAnalysisServiceTests
{
    [Fact]
    public async Task AnalyzeReviewAsync_SavesParsedAnalysisResult()
    {
        await using var db = CreateDbContext();
        await SeedPendingReviewAsync(db);
        var llm = Substitute.For<ILlmClient>();
        llm.AnalyzeReviewAsync(Arg.Any<string>(), Arg.Any<string>())
            .Returns(new LlmReviewAnalysis(
                0.76,
                "Положительный",
                ["lecture structure", "practical examples"],
                true,
                "{\"quality_score\":0.76,\"sentiment\":\"Положительный\"}"));
        var gamification = Substitute.For<IGamificationService>();
        gamification.AwardCoinsAsync(
                Arg.Any<int>(),
                Arg.Any<int>(),
                Arg.Any<CoinTransactionType>(),
                Arg.Any<int?>(),
                Arg.Any<int?>(),
                Arg.Any<string?>())
            .Returns(Task.CompletedTask);
        gamification.CheckAndAwardAchievementsAsync(Arg.Any<int>()).Returns(Task.CompletedTask);
        var service = new LlmAnalysisService(db, llm, gamification, NullLogger<LlmAnalysisService>.Instance);

        await service.AnalyzeReviewAsync(1);

        var review = await db.Reviews.SingleAsync(r => r.Id == 1);
        Assert.Equal(ReviewLlmStatus.Analyzed, review.LlmStatus);
        Assert.Equal(ReviewSentiment.Positive, review.Sentiment);
        Assert.Equal(0.76, review.QualityScore);
        Assert.True(review.IsInformative);
        Assert.Equal(["lecture structure", "practical examples"], review.LlmTags!);
        Assert.Equal("{\"quality_score\":0.76,\"sentiment\":\"Положительный\"}", review.LlmRawOutput);
        await gamification.Received(1).AwardCoinsAsync(
            1,
            10,
            CoinTransactionType.ReviewReward,
            1,
            null,
            "Informative review reward");
    }

    private static async Task SeedPendingReviewAsync(AppDbContext db)
    {
        db.Users.Add(new User { Id = 1, Email = "student@test.local", DisplayName = "Student" });
        db.Courses.Add(new Course { Id = 1, Name = "Course" });
        db.Lectures.Add(new Lecture
        {
            Id = 1,
            CourseId = 1,
            Title = "Lecture",
            StartsAt = DateTime.UtcNow.AddDays(-1),
            EndsAt = DateTime.UtcNow.AddDays(-1).AddHours(2),
            IsOpen = true,
            MaxEnrollments = 30
        });
        db.Reviews.Add(new Review
        {
            Id = 1,
            LectureId = 1,
            UserId = 1,
            Rating = ReviewRating.Like,
            Text = "Useful review",
            LlmStatus = ReviewLlmStatus.Pending
        });
        await db.SaveChangesAsync();
    }

    private static AppDbContext CreateDbContext()
    {
        var options = new DbContextOptionsBuilder<AppDbContext>()
            .UseInMemoryDatabase($"LlmAnalysisServiceTests_{Guid.NewGuid()}")
            .Options;
        return new AppDbContext(options);
    }
}
