using System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text;
using CashLineERP.Contracts.Parties;
using CashLineERP.Infrastructure.Persistence;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace CashLineERP.Api.Tests;

public sealed class ComplianceDocumentUploadQaTests : IClassFixture<ApiTestFactory>
{
    private readonly HttpClient _client;
    private readonly ApiTestFactory _factory;

    public ComplianceDocumentUploadQaTests(ApiTestFactory factory)
    {
        _factory = factory;
        _client = factory.CreateClient();
    }

    [Fact]
    public async Task Public_Onboarding_Upload_Returns_Managed_Metadata_For_Pdf()
    {
        using var content = CreateMultipartContent("COMMERCIAL_REGISTER", "supplier", "commercial-register.pdf", "application/pdf", "%PDF-1.7 test");

        var response = await _client.PostAsync("/api/v1/public/onboarding/compliance-documents/upload", content);

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        var payload = await response.Content.ReadFromJsonAsync<ComplianceDocumentUploadResponse>();
        Assert.NotNull(payload);
        Assert.Equal("COMMERCIAL_REGISTER", payload!.DocumentType);
        Assert.Equal("commercial-register.pdf", payload.FileName);
        Assert.Equal("application/pdf", payload.ContentType);
        Assert.StartsWith("managed://party-compliance/public-supplier/", payload.StorageReference, StringComparison.Ordinal);
    }

    [Fact]
    public async Task Internal_Party_Compliance_Upload_Stores_File_And_Records_Document()
    {
        await _client.AuthenticateAsInternalAsync();
        using var content = CreateMultipartContent("VAT_CERTIFICATE", null, "vat-certificate.png", "image/png", "fakepng");

        var response = await _client.PostAsync("/api/v1/parties/1/compliance-documents/upload", content);

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        var payload = await response.Content.ReadFromJsonAsync<BusinessPartyComplianceDocumentResponse>();
        Assert.NotNull(payload);
        Assert.Equal(1, payload!.PartyId);
        Assert.Equal("VAT_CERTIFICATE", payload.DocumentType);
        Assert.Equal("vat-certificate.png", payload.FileName);
        Assert.Equal("image/png", payload.ContentType);
        Assert.StartsWith("managed://party-compliance/internal-party-1/", payload.StorageReference, StringComparison.Ordinal);

        using var scope = _factory.Services.CreateScope();
        var dbContext = scope.ServiceProvider.GetRequiredService<CashLineErpDbContext>();
        var document = await dbContext.DocumentLinks.SingleAsync(item => item.Id == payload.DocumentLinkId);
        Assert.Equal("BUSINESS_PARTY", document.EntityName);
    }

    [Fact]
    public async Task External_Party_Compliance_Upload_Stores_File_And_Records_Document()
    {
        await _client.AuthenticateAsSupplierAsync();
        using var content = CreateMultipartContent("TAX_CARD", null, "tax-card.jpg", "image/jpeg", "fakejpg");

        var response = await _client.PostAsync("/api/v1/external/parties/1/compliance-documents/upload", content);

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        var payload = await response.Content.ReadFromJsonAsync<BusinessPartyComplianceDocumentResponse>();
        Assert.NotNull(payload);
        Assert.Equal(1, payload!.PartyId);
        Assert.Equal("TAX_CARD", payload.DocumentType);
        Assert.Equal("tax-card.jpg", payload.FileName);
        Assert.Equal("image/jpeg", payload.ContentType);
        Assert.StartsWith("managed://party-compliance/external-party-1/", payload.StorageReference, StringComparison.Ordinal);
    }

    private static MultipartFormDataContent CreateMultipartContent(
        string documentType,
        string? subjectTypeCode,
        string fileName,
        string contentType,
        string body)
    {
        var content = new MultipartFormDataContent();
        content.Add(new StringContent(documentType), "documentType");

        if (!string.IsNullOrWhiteSpace(subjectTypeCode))
        {
            content.Add(new StringContent(subjectTypeCode), "subjectTypeCode");
        }

        var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes(body));
        fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
        content.Add(fileContent, "file", fileName);

        return content;
    }
}
