using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Moq;
using NexusReader.Application.Abstractions.Persistence;
using NexusReader.Application.Queries.Recommendations;
using NexusReader.Infrastructure.Queries;
using Xunit;

namespace NexusReader.Application.Tests.Queries;

public class GetContextualRecommendationsQueryTests
{
    private readonly Mock<IUserReadingStateStore> _readingStateStoreMock;
    private readonly Mock<IUserLibraryStore> _libraryStoreMock;
    private readonly Mock<IVectorSearchStore> _vectorSearchStoreMock;
    private readonly Mock<ILogger<GetContextualRecommendationsQueryHandler>> _loggerMock;
    private readonly GetContextualRecommendationsQueryHandler _handler;

    public GetContextualRecommendationsQueryTests()
    {
        _readingStateStoreMock = new Mock<IUserReadingStateStore>();
        _libraryStoreMock = new Mock<IUserLibraryStore>();
        _vectorSearchStoreMock = new Mock<IVectorSearchStore>();
        _loggerMock = new Mock<ILogger<GetContextualRecommendationsQueryHandler>>();

        _handler = new GetContextualRecommendationsQueryHandler(
            _readingStateStoreMock.Object,
            _libraryStoreMock.Object,
            _vectorSearchStoreMock.Object,
            _loggerMock.Object
        );
    }

    [Fact]
    public async Task Handle_WithNoActiveReadingState_ReturnsEmptyRecommendations()
    {
        // Arrange
        var userId = "user-123";
        _readingStateStoreMock.Setup(s => s.GetActiveReadingStateAsync(userId, It.IsAny<CancellationToken>()))
            .ReturnsAsync((null, null, null));

        var query = new GetContextualRecommendationsQuery(userId);

        // Act
        var result = await _handler.Handle(query, CancellationToken.None);

        // Assert
        result.IsSuccess.Should().BeTrue();
        result.Value.Recommendations.Should().BeEmpty();
    }

    [Fact]
    public async Task Handle_WithActiveReadingState_PerformsSimilaritySearchAndReturnsRecommendations()
    {
        // Arrange
        var userId = "user-123";
        var activeEbookId = Guid.NewGuid();
        var activeChapterId = "chapter-1";
        var tenantId = "tenant-abc";
        var chapterContent = "Active chapter content description";

        _readingStateStoreMock.Setup(s => s.GetActiveReadingStateAsync(userId, It.IsAny<CancellationToken>()))
            .ReturnsAsync((activeEbookId, activeChapterId, tenantId));

        _readingStateStoreMock.Setup(s => s.GetChapterContentAsync(activeChapterId, It.IsAny<CancellationToken>()))
            .ReturnsAsync(chapterContent);

        // Mock vector search results using clean VectorChunk list
        var targetEbookId1 = Guid.NewGuid();
        var targetEbookId2 = Guid.NewGuid();

        var mockChunks = new List<VectorChunk>
        {
            new VectorChunk(
                Content: "Result pattern details",
                EbookId: targetEbookId1.ToString(),
                Score: 0.88,
                MetadataJson: "",
                BookTitle: "Clean Architecture deep dive",
                ChapterTitle: "Chapter 3: Result Pattern"
            ),
            new VectorChunk(
                Content: "Performance optimizations",
                EbookId: targetEbookId2.ToString(),
                Score: 0.72,
                MetadataJson: "",
                BookTitle: "Advanced C# 14",
                ChapterTitle: "Chapter 5: Span and Performance"
            )
        };

        _vectorSearchStoreMock.Setup(v => v.SearchGlobalExcludeAsync(
                chapterContent,
                tenantId,
                activeEbookId,
                2,
                It.IsAny<CancellationToken>()))
            .ReturnsAsync(mockChunks);

        // User owns the second book but not the first one
        _libraryStoreMock.Setup(l => l.GetOwnedBookIdsAsync(userId, It.IsAny<CancellationToken>()))
            .ReturnsAsync(new List<Guid> { targetEbookId2 });

        var query = new GetContextualRecommendationsQuery(userId);

        // Act
        var result = await _handler.Handle(query, CancellationToken.None);

        // Assert
        result.IsSuccess.Should().BeTrue();
        result.Value.Recommendations.Should().HaveCount(2);

        var firstRec = result.Value.Recommendations.First();
        firstRec.BookTitle.Should().Be("Clean Architecture deep dive");
        firstRec.ChapterTitle.Should().Be("Chapter 3: Result Pattern");
        firstRec.MatchPercentage.Should().Be(88);
        firstRec.IsPremiumUpsell.Should().BeTrue(); // User does not own book 1
        firstRec.TargetBookId.Should().Be(targetEbookId1);

        var secondRec = result.Value.Recommendations.Last();
        secondRec.BookTitle.Should().Be("Advanced C# 14");
        secondRec.ChapterTitle.Should().Be("Chapter 5: Span and Performance");
        secondRec.MatchPercentage.Should().Be(72);
        secondRec.IsPremiumUpsell.Should().BeFalse(); // User owns book 2
        secondRec.TargetBookId.Should().Be(targetEbookId2);
    }
}
