using FluentAssertions;
using foodmarket.Application.Common.Tenancy;
using foodmarket.Infrastructure.Integrations.MoySklad;
using foodmarket.Infrastructure.Persistence;
// Двусмысленность ImportJobStatus: тесты используют только in-process snapshot
// API (registry.Create/Save/Get), поэтому ссылаемся на MoySklad-namespace.
using ImportJobStatus = foodmarket.Infrastructure.Integrations.MoySklad.ImportJobStatus;
using foodmarket.IntegrationTests.Support;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Xunit;

namespace foodmarket.IntegrationTests;

/// <summary>TD-5: ImportJob теперь persisted в БД. Тест проверяет, что
/// прогресс сохраняется через границу «рестарта реестра» (новый scope =
/// новая ConcurrentDictionary в старой версии) — но мы читаем из БД,
/// поэтому job остаётся видимым.</summary>
[Collection(ApiCollection.Name)]
public class ImportJobPersistenceTests
{
    private readonly ApiFactory _factory;
    public ImportJobPersistenceTests(ApiFactory factory) => _factory = factory;

    [Fact]
    public async Task Created_job_survives_across_registry_instances()
    {
        // 1) Сигнин чтобы получить orgId, потом руками используем registry.
        var api = new ApiActor(_factory.CreateClient());
        await api.SignupAndLoginAsync($"impjob-{Guid.NewGuid():N}");
        var orgId = await GetOrgIdAsync(api);

        using var scope1 = _factory.Services.CreateScope();
        var registry = _factory.Services.GetRequiredService<ImportJobRegistry>();

        Guid jobId;
        using (foodmarket.Api.Infrastructure.Tenancy.HttpContextTenantContext.UseOverride(orgId))
        {
            var job = registry.Create("products");
            job.Stage = "Импорт страниц 3/10";
            job.Total = 100;
            job.Created = 30;
            await registry.SaveAsync(job);
            jobId = job.Id;
        }

        // 2) В новом scope (имитация после-рестарта) Get(id) тянет из БД,
        // не из in-memory ConcurrentDictionary. State сохранён.
        using (foodmarket.Api.Infrastructure.Tenancy.HttpContextTenantContext.UseOverride(orgId))
        {
            var reloaded = registry.Get(jobId);
            reloaded.Should().NotBeNull();
            reloaded!.Kind.Should().Be("products");
            reloaded.Stage.Should().Be("Импорт страниц 3/10");
            reloaded.Total.Should().Be(100);
            reloaded.Created.Should().Be(30);
            reloaded.Status.Should().Be(ImportJobStatus.Running);
        }
    }

    [Fact]
    public async Task RecentlyFinished_returns_completed_jobs_from_db()
    {
        var api = new ApiActor(_factory.CreateClient());
        await api.SignupAndLoginAsync($"impjob-rf-{Guid.NewGuid():N}");
        var orgId = await GetOrgIdAsync(api);

        var registry = _factory.Services.GetRequiredService<ImportJobRegistry>();
        using (foodmarket.Api.Infrastructure.Tenancy.HttpContextTenantContext.UseOverride(orgId))
        {
            var job = registry.Create("products");
            job.Status = ImportJobStatus.Succeeded;
            job.FinishedAt = DateTime.UtcNow;
            job.Created = 5;
            await registry.SaveAsync(job);

            var finished = registry.RecentlyFinished(10);
            finished.Should().Contain(j => j.Id == job.Id && j.Status == ImportJobStatus.Succeeded);
        }
    }

    [Fact]
    public async Task Tenant_isolation_for_import_jobs()
    {
        var a = new ApiActor(_factory.CreateClient());
        var b = new ApiActor(_factory.CreateClient());
        await a.SignupAndLoginAsync($"impjob-iso-a-{Guid.NewGuid():N}");
        await b.SignupAndLoginAsync($"impjob-iso-b-{Guid.NewGuid():N}");
        var orgA = await GetOrgIdAsync(a);
        var orgB = await GetOrgIdAsync(b);

        var registry = _factory.Services.GetRequiredService<ImportJobRegistry>();
        Guid jobIdA;
        using (foodmarket.Api.Infrastructure.Tenancy.HttpContextTenantContext.UseOverride(orgA))
        {
            var job = registry.Create("products");
            await registry.SaveAsync(job);
            jobIdA = job.Id;
        }

        // B не видит джоб A через registry.Get (query-filter по OrganizationId).
        using (foodmarket.Api.Infrastructure.Tenancy.HttpContextTenantContext.UseOverride(orgB))
        {
            registry.Get(jobIdA).Should().BeNull();
        }
    }

    private static async Task<Guid> GetOrgIdAsync(ApiActor api)
    {
        var me = await api.GetJsonAsync("/api/me");
        return Guid.Parse(me.GetProperty("orgId").GetString()!);
    }
}
