using System;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Moq;
using NexusReader.Application.Abstractions.Persistence;
using NexusReader.Application.Commands.Quiz;
using NexusReader.Data.Persistence;
using NexusReader.Domain.Entities;
using NexusReader.Infrastructure.Persistence;
using Xunit;

namespace NexusReader.Application.Tests.Commands;

public class SubmitQuizResultCommandHandlerTests
{
    private readonly Mock<IQuizResultRepository> _repositoryMock;

    public SubmitQuizResultCommandHandlerTests()
    {
        _repositoryMock = new Mock<IQuizResultRepository>();
    }

    [Fact]
    public async Task Handle_WithValidRequest_PersistsQuizResultToDatabase()
    {
        // Arrange
        var user = new NexusUser
        {
            Id = "user-abc",
            UserName = "testuser",
            Email = "test@example.com",
            TenantId = "tenant-xyz",
            SubscriptionPlanId = 1
        };

        _repositoryMock.Setup(r => r.FindUserByIdAsync("user-abc", It.IsAny<CancellationToken>()))
            .ReturnsAsync(user);

        QuizResult? capturedQuizResult = null;
        _repositoryMock.Setup(r => r.AddQuizResult(It.IsAny<QuizResult>()))
            .Callback<QuizResult>(q => capturedQuizResult = q);

        _repositoryMock.Setup(r => r.SaveChangesAsync(It.IsAny<CancellationToken>()))
            .ReturnsAsync(1);

        var command = new SubmitQuizResultCommand(
            UserId: "user-abc",
            Topic: "Sprawdzian: .NET 10",
            Score: 4,
            TotalQuestions: 5
        );

        var handler = new SubmitQuizResultCommandHandler(_repositoryMock.Object);

        // Act
        var result = await handler.Handle(command, CancellationToken.None);

        // Assert
        result.IsSuccess.Should().BeTrue();
        capturedQuizResult.Should().NotBeNull();
        capturedQuizResult!.Topic.Should().Be("Sprawdzian: .NET 10");
        capturedQuizResult.Score.Should().Be(4);
        capturedQuizResult.TotalQuestions.Should().Be(5);
        capturedQuizResult.TenantId.Should().Be("tenant-xyz");

        _repositoryMock.Verify(r => r.AddQuizResult(It.IsAny<QuizResult>()), Times.Once);
        _repositoryMock.Verify(r => r.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once);
    }

    [Fact]
    public async Task Handle_WithNonExistentUser_ReturnsFailureResult()
    {
        // Arrange
        _repositoryMock.Setup(r => r.FindUserByIdAsync("non-existent", It.IsAny<CancellationToken>()))
            .ReturnsAsync((NexusUser?)null);

        var command = new SubmitQuizResultCommand(
            UserId: "non-existent",
            Topic: "Sprawdzian: .NET 10",
            Score: 4,
            TotalQuestions: 5
        );

        var handler = new SubmitQuizResultCommandHandler(_repositoryMock.Object);

        // Act
        var result = await handler.Handle(command, CancellationToken.None);

        // Assert
        result.IsFailed.Should().BeTrue();
        result.Errors.Should().ContainSingle(e => e.Message == "User not found.");

        _repositoryMock.Verify(r => r.AddQuizResult(It.IsAny<QuizResult>()), Times.Never);
        _repositoryMock.Verify(r => r.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Never);
    }
}
