using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Library.Collections;
using TeleWave.Infrastructure.Persistence;
using Xunit;

namespace TeleWave.Integration.Tests;

/// <summary>
/// Проверка переводимости запросов в SQL. Соединение не открывается: <c>ToQueryString</c> компилирует
/// запрос и падает ровно там, где падал бы прод («The LINQ expression could not be translated»).
/// Поэтому Docker не нужен, и такие ошибки ловятся быстро.
///
/// Повод: карточка шоу отвечала 500, потому что сортировка стояла после сборки DTO — EF не переводит
/// порядок по свойству record'а.
/// </summary>
public sealed class QueryTranslationTests : IDisposable
{
    private readonly AppDbContext _db = new(
        new DbContextOptionsBuilder<AppDbContext>()
            // Сервера по адресу нет и не требуется — запрос только компилируется.
            .UseNpgsql("Host=127.0.0.1;Port=1;Database=telewave;Username=u;Password=p")
            .Options
    );

    [Fact]
    public void ShowCollections_Translates()
    {
        var showId = Guid.NewGuid();

        var sql = _db
            .CollectionItems.AsNoTracking()
            .Where(i => i.ShowId == showId)
            .Join(
                _db.Collections.AsNoTracking(),
                item => item.CollectionId,
                collection => collection.Id,
                (item, collection) =>
                    new
                    {
                        collection.Id,
                        collection.Name,
                        item.Position,
                    }
            )
            .OrderBy(c => c.Name)
            .Select(c => new ShowCollectionRefDto(c.Id, c.Name, c.Position))
            .ToQueryString();

        Assert.Contains("ORDER BY", sql, StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public void ShowCollections_OrderingAfterProjection_DoesNotTranslate()
    {
        // Зафиксировано намеренно: именно эта форма роняла карточку шоу в 500. Если EF когда-нибудь
        // научится её переводить, тест упадёт — и это будет поводом упростить запрос обратно.
        var showId = Guid.NewGuid();

        var query = _db
            .CollectionItems.AsNoTracking()
            .Where(i => i.ShowId == showId)
            .Join(
                _db.Collections.AsNoTracking(),
                item => item.CollectionId,
                collection => collection.Id,
                (item, collection) =>
                    new ShowCollectionRefDto(collection.Id, collection.Name, item.Position)
            )
            .OrderBy(c => c.Name);

        Assert.Throws<InvalidOperationException>(() => query.ToQueryString());
    }

    public void Dispose() => _db.Dispose();
}
