using System.Text.Json;
using Tiku.Application.Learning;
using Tiku.Domain.Common;
using Tiku.Domain.Learning;

namespace Tiku.UnitTests.Learning;

public sealed class QuestionGraderTests
{
    [Fact]
    public void Choice_requires_exactly_one_matching_index()
    {
        var result = Grade("choice", 1, selected: [1]);

        Assert.Equal(AnswerGradingStatus.Correct, result.Status);
        Assert.True(result.IsCorrect);
        Assert.Equal(5, result.AwardedScore);
    }

    [Fact]
    public void Multiple_choice_compares_deduplicated_unordered_sets()
    {
        var result = Grade(
            "multiple_choice",
            correctIndices: JsonSerializer.SerializeToElement(new[] { 2, 0 }),
            selected: [0, 2, 2]);

        Assert.Equal(AnswerGradingStatus.Correct, result.Status);
    }

    [Theory]
    [InlineData("对", "true")]
    [InlineData("false", "错")]
    public void True_false_normalizes_supported_boolean_values(string expected, string actual)
    {
        var result = Grade("true_false", correctText: expected, answerText: actual);

        Assert.Equal(AnswerGradingStatus.Correct, result.Status);
    }

    [Fact]
    public void Fill_blank_normalizes_unicode_case_and_whitespace()
    {
        var rules = JsonSerializer.SerializeToElement(new { acceptedAnswers = new[] { "Entity Framework" } });

        var result = Grade("fill_blank", correctText: "EF Core", answerText: "  ENTITY   FRAMEWORK ", rules: rules);

        Assert.Equal(AnswerGradingStatus.Correct, result.Status);
    }

    [Theory]
    [InlineData("short_answer")]
    [InlineData("reading")]
    [InlineData("programming")]
    public void Subjective_questions_remain_pending_review(string type)
    {
        var result = Grade(type, answerText: "student answer");

        Assert.Equal(AnswerGradingStatus.PendingReview, result.Status);
        Assert.Null(result.IsCorrect);
        Assert.Null(result.AwardedScore);
    }

    private static QuestionGradingResult Grade(
        string type,
        int? correctIndex = null,
        JsonElement? correctIndices = null,
        string? correctText = null,
        IReadOnlyCollection<int>? selected = null,
        string? answerText = null,
        JsonElement? rules = null)
    {
        return QuestionGrader.Grade(new QuestionGradingInput(
            type,
            correctIndex,
            correctIndices ?? JsonDefaults.Array(),
            correctText,
            rules ?? JsonDefaults.Object(),
            selected,
            answerText,
            5));
    }
}