using System.Net;
using System.Net.Http.Json;
using CashLineERP.Contracts.Finance;
using CashLineERP.Contracts.Inventory;
using CashLineERP.Contracts.Reporting;

namespace CashLineERP.Api.Tests;

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

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

    [Fact]
    public async Task Core_Report_Endpoints_Return_Report_Read_Models_And_Csv_Exports()
    {
        await _client.AuthenticateAsFinanceMakerAsync();

        var createInvoiceResponse = await _client.PostAsJsonAsync("/api/v1/finance/ar-invoices", new CreateAccountsReceivableInvoiceRequest(
            CustomerId: 2,
            SalesOrderId: 1,
            DispatchOrderId: 1,
            InvoiceType: "TAX",
            InvoiceDate: new DateOnly(2026, 4, 27),
            TaxDate: new DateOnly(2026, 4, 27),
            DueDate: new DateOnly(2026, 4, 30),
            CurrencyCode: "EGP",
            Lines:
            [
                new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 2m, "EA", 32m, "VAT14")
            ]));
        Assert.True(createInvoiceResponse.IsSuccessStatusCode, await createInvoiceResponse.Content.ReadAsStringAsync());
        var createdInvoice = await createInvoiceResponse.Content.ReadFromJsonAsync<AccountsReceivableInvoiceResponse>();
        Assert.NotNull(createdInvoice);

        var submitInvoiceResponse = await _client.PostAsync($"/api/v1/finance/ar-invoices/{createdInvoice!.AccountsReceivableInvoiceId}/submit", null);
        Assert.True(submitInvoiceResponse.IsSuccessStatusCode, await submitInvoiceResponse.Content.ReadAsStringAsync());

        await _client.AuthenticateAsFinanceCheckerAsync();

        var approveInvoiceResponse = await _client.PostAsync($"/api/v1/finance/ar-invoices/{createdInvoice.AccountsReceivableInvoiceId}/approve", null);
        Assert.True(approveInvoiceResponse.IsSuccessStatusCode, await approveInvoiceResponse.Content.ReadAsStringAsync());

        var postInvoiceResponse = await _client.PostAsync($"/api/v1/finance/ar-invoices/{createdInvoice.AccountsReceivableInvoiceId}/post", null);
        Assert.True(postInvoiceResponse.IsSuccessStatusCode, await postInvoiceResponse.Content.ReadAsStringAsync());
        var postedInvoice = await postInvoiceResponse.Content.ReadFromJsonAsync<AccountsReceivableInvoiceResponse>();
        Assert.NotNull(postedInvoice);

        await _client.AuthenticateAsFinanceMakerAsync();

        var createUsdInvoiceResponse = await _client.PostAsJsonAsync("/api/v1/finance/ar-invoices", new CreateAccountsReceivableInvoiceRequest(
            CustomerId: 2,
            SalesOrderId: 1,
            DispatchOrderId: 1,
            InvoiceType: "TAX",
            InvoiceDate: new DateOnly(2026, 4, 28),
            TaxDate: new DateOnly(2026, 4, 28),
            DueDate: new DateOnly(2026, 4, 30),
            CurrencyCode: "USD",
            Lines:
            [
                new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 1m, "EA", 10m, "VAT14")
            ]));
        Assert.True(createUsdInvoiceResponse.IsSuccessStatusCode, await createUsdInvoiceResponse.Content.ReadAsStringAsync());
        var createdUsdInvoice = await createUsdInvoiceResponse.Content.ReadFromJsonAsync<AccountsReceivableInvoiceResponse>();
        Assert.NotNull(createdUsdInvoice);

        var submitUsdInvoiceResponse = await _client.PostAsync($"/api/v1/finance/ar-invoices/{createdUsdInvoice!.AccountsReceivableInvoiceId}/submit", null);
        Assert.True(submitUsdInvoiceResponse.IsSuccessStatusCode, await submitUsdInvoiceResponse.Content.ReadAsStringAsync());

        await _client.AuthenticateAsFinanceCheckerAsync();

        var approveUsdInvoiceResponse = await _client.PostAsync($"/api/v1/finance/ar-invoices/{createdUsdInvoice.AccountsReceivableInvoiceId}/approve", null);
        Assert.True(approveUsdInvoiceResponse.IsSuccessStatusCode, await approveUsdInvoiceResponse.Content.ReadAsStringAsync());

        var postUsdInvoiceResponse = await _client.PostAsync($"/api/v1/finance/ar-invoices/{createdUsdInvoice.AccountsReceivableInvoiceId}/post", null);
        Assert.True(postUsdInvoiceResponse.IsSuccessStatusCode, await postUsdInvoiceResponse.Content.ReadAsStringAsync());
        var postedUsdInvoice = await postUsdInvoiceResponse.Content.ReadFromJsonAsync<AccountsReceivableInvoiceResponse>();
        Assert.NotNull(postedUsdInvoice);

        await _client.AuthenticateAsFinanceMakerAsync();

        var createAdjustmentResponse = await _client.PostAsJsonAsync("/api/v1/inventory/adjustments", new CreateInventoryAdjustmentRequest(
            BranchId: 1,
            WarehouseId: 1,
            AdjustmentDate: new DateOnly(2026, 4, 27),
            ReasonCode: "COUNT_VARIANCE",
            Notes: "HTTP reporting adjustment",
            Lines:
            [
                new CreateInventoryAdjustmentLineRequest(1001, null, 1m, "EA", 18m, "AVAILABLE", "HTTP-RPT-ADJ-1", null, null)
            ]));
        Assert.True(createAdjustmentResponse.IsSuccessStatusCode, await createAdjustmentResponse.Content.ReadAsStringAsync());
        var createdAdjustment = await createAdjustmentResponse.Content.ReadFromJsonAsync<InventoryAdjustmentResponse>();
        Assert.NotNull(createdAdjustment);

        var submitAdjustmentResponse = await _client.PostAsync($"/api/v1/inventory/adjustments/{createdAdjustment!.InventoryAdjustmentId}/submit", null);
        Assert.True(submitAdjustmentResponse.IsSuccessStatusCode, await submitAdjustmentResponse.Content.ReadAsStringAsync());

        await _client.AuthenticateAsFinanceCheckerAsync();

        var approveAdjustmentResponse = await _client.PostAsync($"/api/v1/inventory/adjustments/{createdAdjustment.InventoryAdjustmentId}/approve", null);
        Assert.True(approveAdjustmentResponse.IsSuccessStatusCode, await approveAdjustmentResponse.Content.ReadAsStringAsync());

        var postAdjustmentResponse = await _client.PostAsync($"/api/v1/inventory/adjustments/{createdAdjustment.InventoryAdjustmentId}/post", null);
        Assert.True(postAdjustmentResponse.IsSuccessStatusCode, await postAdjustmentResponse.Content.ReadAsStringAsync());

        var financeReportResponse = await _client.GetAsync("/api/v1/reports/core-finance?dateFrom=2026-04-27&dateTo=2026-04-30");
        Assert.Equal(HttpStatusCode.OK, financeReportResponse.StatusCode);
        var financeReport = await financeReportResponse.Content.ReadFromJsonAsync<CoreFinanceReportResponse>();
        Assert.NotNull(financeReport);
        Assert.Equal("EGP", financeReport!.BaseCurrencyCode);
        Assert.Equal(2, financeReport.PostedAccountsReceivableInvoiceCount);
        Assert.True(financeReport.GeneralLedgerBatchCount >= 1);
        Assert.Contains(financeReport.Rows, row => row.DocumentNumber == postedInvoice!.InvoiceNumber);
        var usdInvoiceRow = financeReport.Rows.Single(row => row.DocumentNumber == postedUsdInvoice!.InvoiceNumber && row.ReportSection == "AR");
        Assert.Equal("USD", usdInvoiceRow.CurrencyCode);
        Assert.Equal("EGP", usdInvoiceRow.BaseCurrencyCode);
        Assert.Equal(49.5m, usdInvoiceRow.FxRateToBase);
        Assert.Equal(Math.Round(postedUsdInvoice.TotalAmount * 49.5m, 2, MidpointRounding.AwayFromZero), usdInvoiceRow.BaseAmount);

        var financeExportResponse = await _client.GetAsync("/api/v1/reports/core-finance/export?dateFrom=2026-04-27&dateTo=2026-04-30");
        Assert.Equal(HttpStatusCode.OK, financeExportResponse.StatusCode);
        Assert.Equal("text/csv", financeExportResponse.Content.Headers.ContentType?.MediaType);
        var financeCsv = await financeExportResponse.Content.ReadAsStringAsync();
        Assert.Contains("BusinessDate,ReportSection,DocumentType,DocumentNumber,PartyCode,CurrencyCode,BaseCurrencyCode,FxRateToBase,Amount,BaseAmount,StatusCode,ReferenceText", financeCsv);
        Assert.Contains(postedInvoice.InvoiceNumber, financeCsv);
        Assert.Contains(postedUsdInvoice.InvoiceNumber, financeCsv);

        var operationsReportResponse = await _client.GetAsync("/api/v1/reports/core-operations?dateFrom=2026-04-27&dateTo=2026-04-30");
        Assert.Equal(HttpStatusCode.OK, operationsReportResponse.StatusCode);
        var operationsReport = await operationsReportResponse.Content.ReadFromJsonAsync<CoreOperationsReportResponse>();
        Assert.NotNull(operationsReport);
        Assert.Equal(1, operationsReport!.InventoryAdjustmentCount);
        Assert.Contains(operationsReport.Rows, row => row.ActivityType == "INVENTORY_ADJUSTMENT");

        var operationsExportResponse = await _client.GetAsync("/api/v1/reports/core-operations/export?dateFrom=2026-04-27&dateTo=2026-04-30");
        Assert.Equal(HttpStatusCode.OK, operationsExportResponse.StatusCode);
        Assert.Equal("text/csv", operationsExportResponse.Content.Headers.ContentType?.MediaType);
        var operationsCsv = await operationsExportResponse.Content.ReadAsStringAsync();
        Assert.Contains("ActivityDate,ActivityType,DocumentNumber", operationsCsv);
        Assert.Contains("INVENTORY_ADJUSTMENT", operationsCsv);
    }
}
