using System.Net;
using System.Net.Http.Json;
using CashLineERP.Contracts.Finance;
using CashLineERP.Contracts.Integration;

namespace CashLineERP.Api.Tests;

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

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

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

        var createEndpointResponse = await _client.PostAsJsonAsync("/api/v1/integrations/endpoints", new CreateIntegrationEndpointRequest(
            EndpointName: "HTTP FX Source",
            IntegrationProviderCode: "FX_SOURCE",
            EnvironmentCode: "UAT",
            DirectionCode: "INBOUND",
            TransportCode: "REST",
            HttpMethodCode: "POST",
            BaseUrl: "https://fx.http.example.com",
            RelativePath: "/quotes",
            AuthenticationModeCode: "API_KEY",
            CredentialReference: "secret://fx/http/key",
            TimeoutSeconds: 20,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 2,
            IsIdempotencyKeyRequired: true,
            Notes: "HTTP FX source"));
        Assert.Equal(HttpStatusCode.OK, createEndpointResponse.StatusCode);
        var createdEndpoint = await createEndpointResponse.Content.ReadFromJsonAsync<IntegrationEndpointResponse>();
        Assert.NotNull(createdEndpoint);

        Assert.Equal(HttpStatusCode.OK, (await _client.PostAsync($"/api/v1/integrations/endpoints/{createdEndpoint!.IntegrationEndpointId}/submit", null)).StatusCode);

        await _client.AuthenticateAsFinanceCheckerAsync();
        Assert.Equal(HttpStatusCode.OK, (await _client.PostAsync($"/api/v1/integrations/endpoints/{createdEndpoint.IntegrationEndpointId}/approve", null)).StatusCode);
        Assert.Equal(HttpStatusCode.OK, (await _client.PostAsync($"/api/v1/integrations/endpoints/{createdEndpoint.IntegrationEndpointId}/activate", null)).StatusCode);

        await _client.AuthenticateAsFinanceMakerAsync();

        var ingestResponse = await _client.PostAsJsonAsync("/api/v1/finance/fx-quotes/ingest", new IngestForeignExchangeQuotesRequest(
            createdEndpoint.IntegrationEndpointId,
            new DateOnly(2026, 4, 20),
            "EGP",
            "HTTP-FX-BATCH-1",
            "Initial batch",
            [
                new IngestForeignExchangeQuoteLineRequest("USD", 48m, "USD-HTTP-1", null)
            ]));
        Assert.Equal(HttpStatusCode.OK, ingestResponse.StatusCode);

        var secondIngestResponse = await _client.PostAsJsonAsync("/api/v1/finance/fx-quotes/ingest", new IngestForeignExchangeQuotesRequest(
            createdEndpoint.IntegrationEndpointId,
            new DateOnly(2026, 4, 25),
            "EGP",
            "HTTP-FX-BATCH-2",
            "Revaluation batch",
            [
                new IngestForeignExchangeQuoteLineRequest("USD", 50m, "USD-HTTP-2", null)
            ]));
        Assert.Equal(HttpStatusCode.OK, secondIngestResponse.StatusCode);

        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, 20),
            TaxDate: new DateOnly(2026, 4, 20),
            DueDate: new DateOnly(2026, 4, 30),
            CurrencyCode: "USD",
            Lines:
            [
                new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 1m, "EA", 10m, "VAT14")
            ]));
        Assert.Equal(HttpStatusCode.OK, createInvoiceResponse.StatusCode);
        var createdInvoice = await createInvoiceResponse.Content.ReadFromJsonAsync<AccountsReceivableInvoiceResponse>();
        Assert.NotNull(createdInvoice);
        Assert.Equal(HttpStatusCode.OK, (await _client.PostAsync($"/api/v1/finance/ar-invoices/{createdInvoice!.AccountsReceivableInvoiceId}/submit", null)).StatusCode);

        await _client.AuthenticateAsFinanceCheckerAsync();
        Assert.Equal(HttpStatusCode.OK, (await _client.PostAsync($"/api/v1/finance/ar-invoices/{createdInvoice.AccountsReceivableInvoiceId}/approve", null)).StatusCode);
        Assert.Equal(HttpStatusCode.OK, (await _client.PostAsync($"/api/v1/finance/ar-invoices/{createdInvoice.AccountsReceivableInvoiceId}/post", null)).StatusCode);

        await _client.AuthenticateAsFinanceMakerAsync();

        var createBillResponse = await _client.PostAsJsonAsync("/api/v1/procurement/ap-bills", new CashLineERP.Contracts.Procurement.CreateAccountsPayableBillRequest(
            SupplierId: 1,
            PurchaseOrderId: 1,
            GoodsReceiptId: 1,
            BillDate: new DateOnly(2026, 4, 20),
            DueDate: new DateOnly(2026, 4, 30),
            CurrencyCode: "USD",
            Lines:
            [
                new CashLineERP.Contracts.Procurement.CreateAccountsPayableBillLineRequest(1, 1001, 50m, "EA", 24m, "VAT14"),
                new CashLineERP.Contracts.Procurement.CreateAccountsPayableBillLineRequest(2, 1002, 30m, "BOX", 50m, "VAT14")
            ]));
        Assert.Equal(HttpStatusCode.OK, createBillResponse.StatusCode);
        var createdBill = await createBillResponse.Content.ReadFromJsonAsync<CashLineERP.Contracts.Procurement.AccountsPayableBillResponse>();
        Assert.NotNull(createdBill);
        Assert.Equal(HttpStatusCode.OK, (await _client.PostAsync($"/api/v1/procurement/ap-bills/{createdBill!.AccountsPayableBillId}/submit", null)).StatusCode);

        await _client.AuthenticateAsFinanceCheckerAsync();
        Assert.Equal(HttpStatusCode.OK, (await _client.PostAsync($"/api/v1/procurement/ap-bills/{createdBill.AccountsPayableBillId}/approve-match", null)).StatusCode);
        Assert.Equal(HttpStatusCode.OK, (await _client.PostAsync($"/api/v1/procurement/ap-bills/{createdBill.AccountsPayableBillId}/post", null)).StatusCode);

        await _client.AuthenticateAsFinanceMakerAsync();
        Assert.Equal(HttpStatusCode.OK, (await _client.PostAsJsonAsync("/api/v1/finance/cash-accounts", new CreateCashAccountRequest(
            "USD-HTTP",
            "USD HTTP Cash",
            "BANK",
            "USD",
            1,
            100m))).StatusCode);

        var createRevaluationResponse = await _client.PostAsJsonAsync("/api/v1/finance/fx-revaluations", new CreateForeignExchangeRevaluationRequest(
            AccountingPeriodId: 1,
            RevaluationDate: new DateOnly(2026, 4, 25),
            IncludeAccountsReceivable: true,
            IncludeAccountsPayable: true,
            IncludeCashAccounts: true,
            Notes: "HTTP FX revaluation"));
        Assert.Equal(HttpStatusCode.OK, createRevaluationResponse.StatusCode);
        var createdRevaluation = await createRevaluationResponse.Content.ReadFromJsonAsync<ForeignExchangeRevaluationResponse>();
        Assert.NotNull(createdRevaluation);
        Assert.Equal("DRAFT", createdRevaluation!.StatusCode);
        Assert.True(createdRevaluation.Lines.Count >= 3);

        var submitResponse = await _client.PostAsync($"/api/v1/finance/fx-revaluations/{createdRevaluation.ForeignExchangeRevaluationId}/submit", null);
        Assert.Equal(HttpStatusCode.OK, submitResponse.StatusCode);

        await _client.AuthenticateAsFinanceCheckerAsync();

        var approveResponse = await _client.PostAsync($"/api/v1/finance/fx-revaluations/{createdRevaluation.ForeignExchangeRevaluationId}/approve", null);
        Assert.Equal(HttpStatusCode.OK, approveResponse.StatusCode);

        var postResponse = await _client.PostAsync($"/api/v1/finance/fx-revaluations/{createdRevaluation.ForeignExchangeRevaluationId}/post", null);
        Assert.Equal(HttpStatusCode.OK, postResponse.StatusCode);
        var postedRevaluation = await postResponse.Content.ReadFromJsonAsync<ForeignExchangeRevaluationResponse>();
        Assert.NotNull(postedRevaluation);
        Assert.Equal("POSTED", postedRevaluation!.StatusCode);
        Assert.NotNull(postedRevaluation.GeneralLedgerBatchId);

        var detailResponse = await _client.GetAsync($"/api/v1/finance/fx-revaluations/{createdRevaluation.ForeignExchangeRevaluationId}");
        Assert.Equal(HttpStatusCode.OK, detailResponse.StatusCode);

        var listResponse = await _client.GetAsync("/api/v1/finance/fx-revaluations");
        Assert.Equal(HttpStatusCode.OK, listResponse.StatusCode);
        var listedRevaluations = await listResponse.Content.ReadFromJsonAsync<ForeignExchangeRevaluationResponse[]>();
        Assert.NotNull(listedRevaluations);
        Assert.Contains(listedRevaluations!, item => item.ForeignExchangeRevaluationId == createdRevaluation.ForeignExchangeRevaluationId);
    }
}
