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

namespace CashLineERP.Api.Tests;

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

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

    [Fact]
    public async Task Supplier_Statement_And_Reconciliation_Endpoints_Return_Internal_Finance_Read_Models()
    {
        using (var scope = _factory.Services.CreateScope())
        {
            var goodsReceiptService = scope.ServiceProvider.GetRequiredService<IGoodsReceiptService>();
            var apBillService = scope.ServiceProvider.GetRequiredService<IAccountsPayableBillService>();
            var apPaymentService = scope.ServiceProvider.GetRequiredService<IAccountsPayablePaymentService>();

            var goodsReceipt = goodsReceiptService.PostGoodsReceipt(
                goodsReceiptService.CreateGoodsReceipt(new CreateGoodsReceiptRequest(
                    BranchId: 1,
                    PurchaseOrderId: 1,
                    SupplierId: 1,
                    ReceivedAtUtc: new DateTime(2026, 5, 6, 9, 0, 0, DateTimeKind.Utc),
                    ReceivedByUserId: 4,
                    InspectionStatus: "ACCEPTED",
                    Lines:
                    [
                        new CreateGoodsReceiptLineRequest(1, 1001, 1, null, 5m, 5m, 0m, "HTTP-SUP-STMT-GRN-1", null)
                    ])).GoodsReceiptId,
                4);

            var apBill = apBillService.CreateBill(new CreateAccountsPayableBillRequest(
                SupplierId: 1,
                PurchaseOrderId: 1,
                GoodsReceiptId: goodsReceipt.GoodsReceiptId,
                BillDate: new DateOnly(2026, 5, 6),
                DueDate: new DateOnly(2026, 5, 11),
                CurrencyCode: "EGP",
                Lines:
                [
                    new CreateAccountsPayableBillLineRequest(1, 1001, 5m, "EA", 20m, "VAT14")
                ]));
            apBillService.SubmitBill(apBill.AccountsPayableBillId, 3);
            var dbContext = scope.ServiceProvider.GetRequiredService<CashLineERP.Infrastructure.Persistence.CashLineErpDbContext>();
            var apBillEntity = dbContext.AccountsPayableBills.Single(entry => entry.Id == apBill.AccountsPayableBillId);
            apBillEntity.RecordMatchReview(4, true, 0m, "Supplier statement HTTP setup");
            apBillEntity.ApproveForPosting(4);
            dbContext.SaveChanges();
            var postedBill = apBillService.PostBill(apBill.AccountsPayableBillId, 4);

            var payment = apPaymentService.CreatePayment(new CreateAccountsPayablePaymentRequest(
                SupplierId: 1,
                PaymentDate: new DateOnly(2026, 5, 16),
                PaymentMethod: "BANK_TRANSFER",
                CurrencyCode: "EGP",
                AmountAmount: 40m,
                ReferenceNumber: "HTTP-SUP-STMT-PAY-001",
                Notes: "HTTP supplier settlement",
                Allocations:
                [
                    new CreateAccountsPayablePaymentAllocationRequest(postedBill.AccountsPayableBillId, 40m, new DateOnly(2026, 5, 16))
                ]));
            apPaymentService.SubmitPayment(payment.AccountsPayablePaymentId, 5);
            apPaymentService.ApprovePayment(payment.AccountsPayablePaymentId, 6);
            apPaymentService.PostPayment(payment.AccountsPayablePaymentId, 6);
        }

        await _client.AuthenticateAsFinanceMakerAsync();

        var generateResponse = await _client.PostAsJsonAsync("/api/v1/finance/supplier-statements", new CreateSupplierStatementRequest(
            SupplierId: 1,
            DateFrom: new DateOnly(2026, 5, 1),
            DateTo: new DateOnly(2026, 5, 31),
            CurrencyCode: "EGP"));
        Assert.Equal(HttpStatusCode.OK, generateResponse.StatusCode);
        var statement = await generateResponse.Content.ReadFromJsonAsync<SupplierStatementResponse>();
        Assert.NotNull(statement);
        Assert.StartsWith("SSTMT-", statement!.StatementNumber);
        Assert.True(statement.ClosingBalanceAmount >= 74m);

        var listResponse = await _client.GetAsync("/api/v1/finance/supplier-statements?supplierId=1");
        Assert.Equal(HttpStatusCode.OK, listResponse.StatusCode);
        var statements = await listResponse.Content.ReadFromJsonAsync<List<SupplierStatementSummaryResponse>>();
        Assert.NotNull(statements);
        Assert.Contains(statements!, item => item.SupplierStatementId == statement.SupplierStatementId);

        var detailResponse = await _client.GetAsync($"/api/v1/finance/supplier-statements/{statement.SupplierStatementId}");
        Assert.Equal(HttpStatusCode.OK, detailResponse.StatusCode);
        var detail = await detailResponse.Content.ReadFromJsonAsync<SupplierStatementResponse>();
        Assert.NotNull(detail);
        Assert.Contains(detail!.Lines, line => line.DocumentType == "AP_PAYMENT");

        var reconciliationListResponse = await _client.GetAsync("/api/v1/finance/supplier-account-reconciliations?supplierId=1&asOfDate=2026-05-31&currencyCode=EGP");
        Assert.Equal(HttpStatusCode.OK, reconciliationListResponse.StatusCode);
        var summaries = await reconciliationListResponse.Content.ReadFromJsonAsync<List<SupplierAccountReconciliationSummaryResponse>>();
        Assert.NotNull(summaries);
        var summary = Assert.Single(summaries!);
        Assert.Equal(statement.SupplierStatementId, summary.LastStatementId);

        var reconciliationDetailResponse = await _client.GetAsync("/api/v1/finance/supplier-account-reconciliations/1?asOfDate=2026-05-31&currencyCode=EGP");
        Assert.Equal(HttpStatusCode.OK, reconciliationDetailResponse.StatusCode);
        var reconciliationDetail = await reconciliationDetailResponse.Content.ReadFromJsonAsync<SupplierAccountReconciliationResponse>();
        Assert.NotNull(reconciliationDetail);
        Assert.Contains(reconciliationDetail!.Lines, line => line.DocumentType == "AP_PAYMENT");
    }
}
