using System.Net;
using System.Net.Http.Json;
using System.IO.Compression;
using CashLineERP.Application.Finance;
using CashLineERP.Application.Procurement;
using CashLineERP.Contracts.Finance;
using CashLineERP.Contracts.Procurement;
using CashLineERP.Contracts.Tax;
using Microsoft.Extensions.DependencyInjection;

namespace CashLineERP.Api.Tests;

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

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

    [Fact]
    public async Task Withholding_Endpoints_Return_AP_And_AR_Summaries_And_Exports()
    {
        long accountsPayableBillId;
        long accountsReceivableInvoiceId;

        using (var scope = _factory.Services.CreateScope())
        {
            var billService = scope.ServiceProvider.GetRequiredService<IAccountsPayableBillService>();
            var invoiceService = scope.ServiceProvider.GetRequiredService<IAccountsReceivableInvoiceService>();

            var bill = billService.CreateBill(new CreateAccountsPayableBillRequest(
                SupplierId: 1,
                PurchaseOrderId: 1,
                GoodsReceiptId: 1,
                BillDate: new DateOnly(2026, 5, 28),
                DueDate: new DateOnly(2026, 5, 31),
                CurrencyCode: "EGP",
                Lines:
                [
                    new CreateAccountsPayableBillLineRequest(1, 1001, 10m, "EA", 20m, "WHT3"),
                    new CreateAccountsPayableBillLineRequest(2, 1002, 2m, "BOX", 100m, "WHT5")
                ]));

            accountsPayableBillId = billService.SubmitBill(bill.AccountsPayableBillId, 3).AccountsPayableBillId;

            var invoice = invoiceService.CreateInvoice(new CreateAccountsReceivableInvoiceRequest(
                CustomerId: 2,
                SalesOrderId: 1,
                DispatchOrderId: 1,
                InvoiceType: "TAX",
                InvoiceDate: new DateOnly(2026, 5, 28),
                TaxDate: new DateOnly(2026, 5, 28),
                DueDate: new DateOnly(2026, 5, 31),
                CurrencyCode: "EGP",
                Lines:
                [
                    new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 5m, "EA", 40m, "WHT1"),
                    new CreateAccountsReceivableInvoiceLineRequest(2, 1002, 2m, "BOX", 100m, "WHT3")
                ]));

            accountsReceivableInvoiceId = AccountsReceivableWorkflowTestHelper
                .SubmitApproveAndPostInvoice(invoiceService, invoice.AccountsReceivableInvoiceId)
                .AccountsReceivableInvoiceId;
        }

        await _client.AuthenticateAsFinanceMakerAsync();

        var billSummaryResponse = await _client.GetAsync($"/api/v1/procurement/ap-bills/{accountsPayableBillId}/withholding-summary");
        Assert.Equal(HttpStatusCode.OK, billSummaryResponse.StatusCode);
        var billSummary = await billSummaryResponse.Content.ReadFromJsonAsync<DocumentWithholdingSummaryResponse>();
        Assert.NotNull(billSummary);
        Assert.Equal(16m, billSummary!.TotalWithholdingAmount);
        Assert.Equal(384m, billSummary.NetSettlementAmount);

        var billExportResponse = await _client.GetAsync($"/api/v1/procurement/ap-bills/{accountsPayableBillId}/withholding-export");
        Assert.Equal(HttpStatusCode.OK, billExportResponse.StatusCode);
        var billExport = await billExportResponse.Content.ReadFromJsonAsync<DocumentWithholdingExportResponse>();
        Assert.NotNull(billExport);
        Assert.Contains("WHT5", billExport!.ContentText, StringComparison.Ordinal);

        var invoiceSummaryResponse = await _client.GetAsync($"/api/v1/finance/ar-invoices/{accountsReceivableInvoiceId}/withholding-summary");
        Assert.Equal(HttpStatusCode.OK, invoiceSummaryResponse.StatusCode);
        var invoiceSummary = await invoiceSummaryResponse.Content.ReadFromJsonAsync<DocumentWithholdingSummaryResponse>();
        Assert.NotNull(invoiceSummary);
        Assert.Equal(8m, invoiceSummary!.TotalWithholdingAmount);
        Assert.Equal(392m, invoiceSummary.NetSettlementAmount);

        var invoiceExportResponse = await _client.GetAsync($"/api/v1/finance/ar-invoices/{accountsReceivableInvoiceId}/withholding-export");
        Assert.Equal(HttpStatusCode.OK, invoiceExportResponse.StatusCode);
        var invoiceExport = await invoiceExportResponse.Content.ReadFromJsonAsync<DocumentWithholdingExportResponse>();
        Assert.NotNull(invoiceExport);
        Assert.Contains("WHT1", invoiceExport!.ContentText, StringComparison.Ordinal);
    }

    [Fact]
    public async Task Export_Download_Endpoints_Stream_Attachment_Content_And_Finance_Review_Package()
    {
        long accountsPayableBillId;
        long accountsReceivableInvoiceId;

        using (var scope = _factory.Services.CreateScope())
        {
            var billService = scope.ServiceProvider.GetRequiredService<IAccountsPayableBillService>();
            var invoiceService = scope.ServiceProvider.GetRequiredService<IAccountsReceivableInvoiceService>();

            var bill = billService.CreateBill(new CreateAccountsPayableBillRequest(
                SupplierId: 1,
                PurchaseOrderId: 1,
                GoodsReceiptId: 1,
                BillDate: new DateOnly(2026, 5, 30),
                DueDate: new DateOnly(2026, 5, 31),
                CurrencyCode: "EGP",
                Lines:
                [
                    new CreateAccountsPayableBillLineRequest(1, 1001, 5m, "EA", 20m, "VAT14"),
                    new CreateAccountsPayableBillLineRequest(2, 1002, 1m, "BOX", 80m, "WHT3")
                ]));

            accountsPayableBillId = billService.SubmitBill(bill.AccountsPayableBillId, 3).AccountsPayableBillId;

            var invoice = invoiceService.CreateInvoice(new CreateAccountsReceivableInvoiceRequest(
                CustomerId: 2,
                SalesOrderId: 1,
                DispatchOrderId: 1,
                InvoiceType: "TAX",
                InvoiceDate: new DateOnly(2026, 5, 30),
                TaxDate: new DateOnly(2026, 5, 30),
                DueDate: new DateOnly(2026, 5, 31),
                CurrencyCode: "EGP",
                Lines:
                [
                    new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 2m, "EA", 32m, "VAT14"),
                    new CreateAccountsReceivableInvoiceLineRequest(2, 1002, 1m, "BOX", 60m, "WHT1")
                ]));

            accountsReceivableInvoiceId = AccountsReceivableWorkflowTestHelper
                .SubmitApproveAndPostInvoice(invoiceService, invoice.AccountsReceivableInvoiceId)
                .AccountsReceivableInvoiceId;
        }

        await _client.AuthenticateAsFinanceMakerAsync();

        var downloadResponse = await _client.GetAsync($"/api/v1/finance/ar-invoices/{accountsReceivableInvoiceId}/vat-breakdown-export?download=true");
        Assert.Equal(HttpStatusCode.OK, downloadResponse.StatusCode);
        Assert.Equal("text/csv", downloadResponse.Content.Headers.ContentType!.MediaType);
        Assert.NotNull(downloadResponse.Content.Headers.ContentDisposition);
        Assert.Equal("attachment", downloadResponse.Content.Headers.ContentDisposition!.DispositionType);
        var downloadedCsv = await downloadResponse.Content.ReadAsStringAsync();
        Assert.Contains("VAT14", downloadedCsv, StringComparison.Ordinal);

        var packageResponse = await _client.GetAsync($"/api/v1/procurement/ap-bills/{accountsPayableBillId}/finance-review-package");
        Assert.Equal(HttpStatusCode.OK, packageResponse.StatusCode);
        Assert.Equal("application/zip", packageResponse.Content.Headers.ContentType!.MediaType);
        Assert.NotNull(packageResponse.Content.Headers.ContentDisposition);
        Assert.Equal("attachment", packageResponse.Content.Headers.ContentDisposition!.DispositionType);

        await using var packageStream = await packageResponse.Content.ReadAsStreamAsync();
        using var packageArchive = new ZipArchive(packageStream, ZipArchiveMode.Read);
        Assert.NotNull(packageArchive.GetEntry("manifest.json"));
        Assert.Contains(packageArchive.Entries, entry => entry.Name.EndsWith(".csv", StringComparison.OrdinalIgnoreCase));
        Assert.Contains(packageArchive.Entries, entry => entry.Name.EndsWith(".json", StringComparison.OrdinalIgnoreCase) && entry.Name != "manifest.json");

        var arPackageResponse = await _client.GetAsync($"/api/v1/finance/ar-invoices/{accountsReceivableInvoiceId}/finance-review-package");
        Assert.Equal(HttpStatusCode.OK, arPackageResponse.StatusCode);
        await using var arPackageStream = await arPackageResponse.Content.ReadAsStreamAsync();
        using var arPackageArchive = new ZipArchive(arPackageStream, ZipArchiveMode.Read);
        var manifestEntry = arPackageArchive.GetEntry("manifest.json");
        Assert.NotNull(manifestEntry);
        using var manifestStream = manifestEntry!.Open();
        using var reader = new StreamReader(manifestStream);
        var manifestContent = await reader.ReadToEndAsync();
        Assert.Contains("AR_INVOICE", manifestContent, StringComparison.Ordinal);
    }
}
