using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using FluentAssertions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

/// <summary>
/// Tests for barcode-assisted batch creation via cover sheet codes.
/// </summary>
[Collection("Database")]
public class CoverSheetBatchTests : IAsyncLifetime
{
    private readonly ApiFixture _fixture;
    private HttpClient _intakeClient = null!;

    public CoverSheetBatchTests(ApiFixture fixture) => _fixture = fixture;

    public async Task InitializeAsync()
    {
        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        await DbResetHelper.ResetAsync(db);
        await DataSeeder.SeedAsync(db);
        _intakeClient = await AuthHelper.LoginAsync(_fixture, "intake1");
    }

    public Task DisposeAsync() => Task.CompletedTask;

    [Fact]
    public async Task Create_WithCoverSheetCode_CreatesBatchAndRedeemsCoverSheet()
    {
        var code = await GenerateCoverSheetCodeAsync("VITALS_SHEET", "BACKFILL");

        var response = await UploadWithCoverSheetAsync(code);

        response.StatusCode.Should().Be(HttpStatusCode.Created);

        var body = await response.Content.ReadFromJsonAsync<JsonElement>();
        var batchId = body.GetProperty("data").GetProperty("id").GetGuid();
        body.GetProperty("data").GetProperty("batchType").GetString()
            .Should().Be("VITALS_SHEET");
        body.GetProperty("data").GetProperty("track").GetString()
            .Should().Be("BACKFILL");

        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        var sheet = await db.CoverSheets.FirstAsync(c => c.Code == code);
        sheet.IsUsed.Should().BeTrue();
        sheet.BatchId.Should().Be(batchId);
        sheet.UsedAt.Should().NotBeNull();
    }

    [Fact]
    public async Task Create_WithUsedCoverSheetCode_Returns409()
    {
        var code = await GenerateCoverSheetCodeAsync("VITALS_SHEET", "BACKFILL");

        var first = await UploadWithCoverSheetAsync(code);
        first.EnsureSuccessStatusCode();

        var second = await UploadWithCoverSheetAsync(code);
        second.StatusCode.Should().Be(HttpStatusCode.Conflict);

        var body = await second.Content.ReadFromJsonAsync<JsonElement>();
        body.GetProperty("error").GetProperty("code").GetString()
            .Should().Be("COVER_SHEET_ALREADY_USED");
    }

    [Fact]
    public async Task Create_WithUnknownCoverSheetCode_Returns404()
    {
        var response = await UploadWithCoverSheetAsync("VCR-CS-DEADBEEF");

        response.StatusCode.Should().Be(HttpStatusCode.NotFound);

        var body = await response.Content.ReadFromJsonAsync<JsonElement>();
        body.GetProperty("error").GetProperty("code").GetString()
            .Should().Be("COVER_SHEET_NOT_FOUND");
    }

    [Fact]
    public async Task Create_WithCoverSheetPreAssigned_AutoAssignsBatch()
    {
        Guid entryUserId;
        using (var scope = _fixture.Services.CreateScope())
        {
            var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
            entryUserId = await BatchSeedHelper.UserIdAsync(db, "entry1");
        }

        var code = await GenerateCoverSheetCodeAsync(
            "LAB_RESULTS", "BACKFILL", assignToUserId: entryUserId);

        var response = await UploadWithCoverSheetAsync(code);
        response.EnsureSuccessStatusCode();

        var body = await response.Content.ReadFromJsonAsync<JsonElement>();
        body.GetProperty("data").GetProperty("batchType").GetString()
            .Should().Be("LAB_RESULTS");
        body.GetProperty("data").GetProperty("enteredByUserId").GetGuid()
            .Should().Be(entryUserId);
        body.GetProperty("data").GetProperty("status").GetString()
            .Should().Be("IN_ENTRY");
    }

    private async Task<string> GenerateCoverSheetCodeAsync(
        string batchType,
        string track,
        Guid? assignToUserId = null)
    {
        var payload = new
        {
            count = 1,
            batchType,
            track,
            assignToUserId
        };

        var response = await _intakeClient.PostAsJsonAsync("/api/v1/cover-sheets/generate", payload);
        response.EnsureSuccessStatusCode();

        var body = await response.Content.ReadFromJsonAsync<JsonElement>();
        return body.GetProperty("data")[0].GetProperty("code").GetString()!;
    }

    private async Task<HttpResponseMessage> UploadWithCoverSheetAsync(string coverSheetCode)
    {
        var fileContent = new ByteArrayContent(
            System.Text.Encoding.ASCII.GetBytes(
                $"%PDF-1.4\n%%EOF\n%test-{Guid.NewGuid()}"));
        fileContent.Headers.ContentType =
            new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");

        var formData = new MultipartFormDataContent
        {
            { fileContent, "file", "test.pdf" },
            { new StringContent(coverSheetCode), "coverSheetCode" }
        };

        return await _intakeClient.PostAsync("/api/v1/digitization-batches", formData);
    }
}
