using System.Net;
using System.Net.Http.Json;
using CashLineERP.Contracts.Sales;

namespace CashLineERP.Api.Tests;

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

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

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

        var createSalesOrderResponse = await _client.PostAsJsonAsync("/api/v1/sales/orders", new CreateSalesOrderRequest(
            BranchId: 1,
            CustomerId: 2,
            OrderDate: new DateOnly(2026, 4, 30),
            CurrencyCode: "EGP",
            ExchangeRate: 1m,
            Lines:
            [
                new CreateSalesOrderLineRequest(1001, 1, 150m, "EA", 32m, "VAT14")
            ]));

        Assert.True(createSalesOrderResponse.IsSuccessStatusCode, await createSalesOrderResponse.Content.ReadAsStringAsync());
        var salesOrder = await createSalesOrderResponse.Content.ReadFromJsonAsync<SalesOrderResponse>();
        Assert.NotNull(salesOrder);

        var submitResponse = await _client.PostAsync($"/api/v1/sales/orders/{salesOrder!.SalesOrderId}/submit", null);
        Assert.True(submitResponse.IsSuccessStatusCode, await submitResponse.Content.ReadAsStringAsync());

        var submittedOrder = await submitResponse.Content.ReadFromJsonAsync<SalesOrderResponse>();
        Assert.NotNull(submittedOrder);
        Assert.Equal("ON_HOLD", submittedOrder!.CreditStatusCode);

        var creditControlResponse = await _client.GetAsync("/api/v1/sales/customers/2/credit-control?currencyCode=EGP&asOfDate=2026-04-30");
        Assert.True(creditControlResponse.IsSuccessStatusCode, await creditControlResponse.Content.ReadAsStringAsync());

        var creditControl = await creditControlResponse.Content.ReadFromJsonAsync<CustomerCreditControlResponse>();
        Assert.NotNull(creditControl);
        Assert.Equal("EGP", creditControl!.BaseCurrencyCode);
        Assert.True(creditControl!.ShouldHoldNewOrders);

        await _client.AuthenticateAsFinanceCheckerAsync();

        var releaseResponse = await _client.PostAsJsonAsync($"/api/v1/sales/orders/{salesOrder.SalesOrderId}/credit-release", new ReleaseSalesOrderCreditHoldRequest(
            ActorUserId: 4,
            DecisionCode: "RELEASE",
            Notes: "HTTP finance release approved."));

        Assert.True(releaseResponse.IsSuccessStatusCode, await releaseResponse.Content.ReadAsStringAsync());
        var releasedOrder = await releaseResponse.Content.ReadFromJsonAsync<SalesOrderResponse>();
        Assert.NotNull(releasedOrder);
        Assert.Equal("RELEASED", releasedOrder!.CreditStatusCode);
    }

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

        var createSalesOrderResponse = await _client.PostAsJsonAsync("/api/v1/sales/orders", new CreateSalesOrderRequest(
            BranchId: 1,
            CustomerId: 2,
            OrderDate: new DateOnly(2026, 5, 1),
            CurrencyCode: "EGP",
            ExchangeRate: 1m,
            Lines:
            [
                new CreateSalesOrderLineRequest(1001, 1, 4m, "EA", 32m, "VAT14")
            ]));

        Assert.True(createSalesOrderResponse.IsSuccessStatusCode, await createSalesOrderResponse.Content.ReadAsStringAsync());
        var salesOrder = await createSalesOrderResponse.Content.ReadFromJsonAsync<SalesOrderResponse>();
        Assert.NotNull(salesOrder);

        var submitResponse = await _client.PostAsync($"/api/v1/sales/orders/{salesOrder!.SalesOrderId}/submit", null);
        Assert.True(submitResponse.IsSuccessStatusCode, await submitResponse.Content.ReadAsStringAsync());

        var submittedOrder = await submitResponse.Content.ReadFromJsonAsync<SalesOrderResponse>();
        Assert.NotNull(submittedOrder);

        var createDispatchResponse = await _client.PostAsJsonAsync("/api/v1/sales/dispatches", new CreateDispatchOrderRequest(
            BranchId: 1,
            SalesOrderId: salesOrder.SalesOrderId,
            DispatchWarehouseId: 1,
            PlannedShipAtUtc: new DateTime(2026, 5, 1, 10, 0, 0, DateTimeKind.Utc),
            Lines:
            [
                new CreateDispatchOrderLineRequest(submittedOrder!.Lines.First().SalesOrderLineId, 1001, 4m, null, "BATCH-HTTP-RET-001", null)
            ]));

        Assert.True(createDispatchResponse.IsSuccessStatusCode, await createDispatchResponse.Content.ReadAsStringAsync());
        var dispatch = await createDispatchResponse.Content.ReadFromJsonAsync<DispatchOrderResponse>();
        Assert.NotNull(dispatch);

        var postDispatchResponse = await _client.PostAsJsonAsync($"/api/v1/sales/dispatches/{dispatch!.DispatchOrderId}/post", new PostDispatchOrderRequest(
            ActorUserId: 6,
            ShippedAtUtc: new DateTime(2026, 5, 1, 12, 0, 0, DateTimeKind.Utc),
            DeliveredAtUtc: new DateTime(2026, 5, 1, 15, 0, 0, DateTimeKind.Utc),
            ProofOfDeliveryReceiver: "HTTP Return Receiver"));
        Assert.True(postDispatchResponse.IsSuccessStatusCode, await postDispatchResponse.Content.ReadAsStringAsync());

        var createReturnResponse = await _client.PostAsJsonAsync("/api/v1/sales/returns", new CreateSalesReturnRequest(
            BranchId: 1,
            CustomerId: 2,
            SalesOrderId: salesOrder.SalesOrderId,
            DispatchOrderId: dispatch.DispatchOrderId,
            ReturnDate: new DateOnly(2026, 5, 2),
            ReturnWarehouseId: 1,
            ReasonCode: "CUSTOMER_RETURN",
            Notes: "HTTP return flow.",
            Lines:
            [
                new CreateSalesReturnLineRequest(dispatch.Lines.First().DispatchOrderLineId, submittedOrder.Lines.First().SalesOrderLineId, 1001, 2m, null, "BATCH-HTTP-RET-001", null, "HTTP returned qty")
            ]));
        Assert.True(createReturnResponse.IsSuccessStatusCode, await createReturnResponse.Content.ReadAsStringAsync());

        var salesReturn = await createReturnResponse.Content.ReadFromJsonAsync<SalesReturnResponse>();
        Assert.NotNull(salesReturn);

        var submitReturnResponse = await _client.PostAsync($"/api/v1/sales/returns/{salesReturn!.SalesReturnId}/submit", null);
        Assert.True(submitReturnResponse.IsSuccessStatusCode, await submitReturnResponse.Content.ReadAsStringAsync());

        var postReturnResponse = await _client.PostAsync($"/api/v1/sales/returns/{salesReturn.SalesReturnId}/post", null);
        Assert.True(postReturnResponse.IsSuccessStatusCode, await postReturnResponse.Content.ReadAsStringAsync());

        var creditNoteResponse = await _client.PostAsJsonAsync($"/api/v1/sales/returns/{salesReturn.SalesReturnId}/issue-credit-note", new IssueSalesReturnCreditNoteRequest(
            ActorUserId: 4,
            InvoiceDate: new DateOnly(2026, 5, 2),
            TaxDate: new DateOnly(2026, 5, 2),
            DueDate: new DateOnly(2026, 5, 2)));
        Assert.True(creditNoteResponse.IsSuccessStatusCode, await creditNoteResponse.Content.ReadAsStringAsync());

        var returnedWithCreditNote = await creditNoteResponse.Content.ReadFromJsonAsync<SalesReturnResponse>();
        Assert.NotNull(returnedWithCreditNote);
        Assert.NotNull(returnedWithCreditNote!.CreditNoteInvoiceId);

        var creditInvoiceResponse = await _client.GetAsync($"/api/v1/finance/ar-invoices/{returnedWithCreditNote.CreditNoteInvoiceId}");
        Assert.True(creditInvoiceResponse.IsSuccessStatusCode, await creditInvoiceResponse.Content.ReadAsStringAsync());
    }
}
