using System.Net;
using System.Net.Http.Json;
using CashLineERP.Contracts.Internal;
using CashLineERP.Contracts.IslamicFinance;
using CashLineERP.Contracts.Inventory;
using CashLineERP.Contracts.Sales;

namespace CashLineERP.Api.Tests;

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

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

    [Fact]
    public async Task Internal_Workbench_Endpoints_Return_Dashboard_Approvals_And_Exceptions()
    {
        await _client.AuthenticateAsInternalAsync();

        var salesOrderResponse = 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(salesOrderResponse.IsSuccessStatusCode, await salesOrderResponse.Content.ReadAsStringAsync());
        var salesOrder = await salesOrderResponse.Content.ReadFromJsonAsync<SalesOrderResponse>();
        Assert.NotNull(salesOrder);

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

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

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

        var dashboardResponse = await _client.GetAsync("/api/v1/internal/dashboard");
        Assert.Equal(HttpStatusCode.OK, dashboardResponse.StatusCode);
        var dashboard = await dashboardResponse.Content.ReadFromJsonAsync<InternalDashboardSummaryResponse>();
        Assert.NotNull(dashboard);
        Assert.True(dashboard!.PendingApprovalCount >= 2);
        Assert.True(dashboard.CreditHoldCount >= 1);

        var approvalsResponse = await _client.GetAsync("/api/v1/internal/work-queues/approvals");
        Assert.Equal(HttpStatusCode.OK, approvalsResponse.StatusCode);
        var approvals = await approvalsResponse.Content.ReadFromJsonAsync<List<InternalApprovalQueueItemResponse>>();
        Assert.NotNull(approvals);
        Assert.Contains(approvals!, item => item.DocumentType == "INV_ADJUSTMENT");
        Assert.Contains(approvals!, item => item.DocumentType == "SALES_ORDER");

        var salesApprovalsResponse = await _client.GetAsync("/api/v1/internal/work-queues/approvals?moduleCode=SALES");
        Assert.Equal(HttpStatusCode.OK, salesApprovalsResponse.StatusCode);
        var salesApprovals = await salesApprovalsResponse.Content.ReadFromJsonAsync<List<InternalApprovalQueueItemResponse>>();
        Assert.NotNull(salesApprovals);
        Assert.All(salesApprovals!, item => Assert.Equal("SALES", item.ModuleCode));

        var exceptionsResponse = await _client.GetAsync("/api/v1/internal/work-queues/exceptions?sourceType=CREDIT_CONTROL");
        Assert.Equal(HttpStatusCode.OK, exceptionsResponse.StatusCode);
        var exceptions = await exceptionsResponse.Content.ReadFromJsonAsync<List<InternalExceptionQueueItemResponse>>();
        Assert.NotNull(exceptions);
        Assert.Contains(exceptions!, item => item.SourceType == "CREDIT_CONTROL" && item.DocumentType == "SALES_ORDER");
    }

    [Fact]
    public async Task Internal_Operations_Endpoints_Return_Dashboard_And_Filtered_Alerts()
    {
        await _client.AuthenticateAsInternalAsync();

        var salesOrderResponse = await _client.PostAsJsonAsync("/api/v1/sales/orders", new CreateSalesOrderRequest(
            BranchId: 1,
            CustomerId: 2,
            OrderDate: new DateOnly(2026, 4, 4),
            CurrencyCode: "EGP",
            ExchangeRate: 1m,
            Lines:
            [
                new CreateSalesOrderLineRequest(1001, 1, 450m, "EA", 32m, "VAT14")
            ]));
        Assert.True(salesOrderResponse.IsSuccessStatusCode, await salesOrderResponse.Content.ReadAsStringAsync());
        var salesOrder = await salesOrderResponse.Content.ReadFromJsonAsync<SalesOrderResponse>();
        Assert.NotNull(salesOrder);

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

        var dashboardResponse = await _client.GetAsync("/api/v1/internal/operations/dashboard");
        Assert.Equal(HttpStatusCode.OK, dashboardResponse.StatusCode);
        var dashboard = await dashboardResponse.Content.ReadFromJsonAsync<InternalOperationalDashboardResponse>();
        Assert.NotNull(dashboard);
        Assert.Equal("OK", dashboard!.ServiceStatus);
        Assert.True(dashboard.CreditHoldCount >= 1);
        Assert.True(dashboard.WarningAlertCount >= 1);

        var alertsResponse = await _client.GetAsync("/api/v1/internal/operations/alerts?severityCode=WARNING&sourceArea=SALES");
        Assert.Equal(HttpStatusCode.OK, alertsResponse.StatusCode);
        var alerts = await alertsResponse.Content.ReadFromJsonAsync<List<InternalOperationalAlertResponse>>();
        Assert.NotNull(alerts);
        Assert.Contains(alerts!, item => item.AlertCode == "CREDIT_HOLD_OPEN" && item.SourceArea == "SALES");

        var monitoringResponse = await _client.GetAsync("/api/v1/internal/workflow-monitoring?itemLimit=5");
        Assert.Equal(HttpStatusCode.OK, monitoringResponse.StatusCode);
        var monitoring = await monitoringResponse.Content.ReadFromJsonAsync<InternalWorkflowMonitoringResponse>();
        Assert.NotNull(monitoring);
        Assert.Equal("OK", monitoring!.ServiceStatus);
        Assert.True(monitoring.RefreshIntervalSeconds >= 10);
        Assert.True(monitoring.Dashboard.PendingApprovalCount >= 1);
        Assert.NotEmpty(monitoring.Alerts);
    }

    [Fact]
    public async Task Internal_Hypercare_Endpoints_Return_Console_Incidents_And_Runbooks()
    {
        await _client.AuthenticateAsInternalAsync();

        var salesOrderResponse = await _client.PostAsJsonAsync("/api/v1/sales/orders", new CreateSalesOrderRequest(
            BranchId: 1,
            CustomerId: 2,
            OrderDate: new DateOnly(2026, 4, 5),
            CurrencyCode: "EGP",
            ExchangeRate: 1m,
            Lines:
            [
                new CreateSalesOrderLineRequest(1001, 1, 520m, "EA", 32m, "VAT14")
            ]));
        Assert.True(salesOrderResponse.IsSuccessStatusCode, await salesOrderResponse.Content.ReadAsStringAsync());
        var salesOrder = await salesOrderResponse.Content.ReadFromJsonAsync<SalesOrderResponse>();
        Assert.NotNull(salesOrder);

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

        var consoleResponse = await _client.GetAsync("/api/v1/internal/hypercare/console");
        Assert.Equal(HttpStatusCode.OK, consoleResponse.StatusCode);
        var console = await consoleResponse.Content.ReadFromJsonAsync<InternalHypercareConsoleResponse>();
        Assert.NotNull(console);
        Assert.Equal("1.0.0-v1-controlled-baseline.0", console!.ReleaseVersion);
        Assert.True(console.RunbookCount >= 6);

        var incidentsResponse = await _client.GetAsync("/api/v1/internal/hypercare/incidents?sourceArea=SALES");
        Assert.Equal(HttpStatusCode.OK, incidentsResponse.StatusCode);
        var incidents = await incidentsResponse.Content.ReadFromJsonAsync<List<InternalHypercareIncidentResponse>>();
        Assert.NotNull(incidents);
        Assert.Contains(incidents!, item => item.IncidentCode == "CREDIT_HOLD_OPEN" && item.RecommendedRunbookCode == "HYPERCARE_TRIAGE");

        var runbooksResponse = await _client.GetAsync("/api/v1/internal/hypercare/runbooks?categoryCode=OPERATIONS");
        Assert.Equal(HttpStatusCode.OK, runbooksResponse.StatusCode);
        var runbooks = await runbooksResponse.Content.ReadFromJsonAsync<List<InternalHypercareRunbookResponse>>();
        Assert.NotNull(runbooks);
        Assert.Contains(runbooks!, item => item.RunbookCode == "HYPERCARE_TRIAGE");

        var runbookDetailResponse = await _client.GetAsync("/api/v1/internal/hypercare/runbooks/CUTOVER");
        Assert.Equal(HttpStatusCode.OK, runbookDetailResponse.StatusCode);
        var runbookDetail = await runbookDetailResponse.Content.ReadFromJsonAsync<InternalHypercareRunbookDetailResponse>();
        Assert.NotNull(runbookDetail);
        Assert.Contains("Cutover Runbook", runbookDetail!.MarkdownContent);
    }

    [Fact]
    public async Task Internal_Workbench_Endpoints_Expose_Islamic_Finance_Approvals_And_Exceptions()
    {
        await _client.AuthenticateAsInternalAsync();

        var partnerResponse = await _client.PostAsJsonAsync("/api/v1/islamic-finance/partners", new CreateIslamicFinancePartnerLenderRequest
        {
            PartnerLenderPartyId = 1,
            DefaultCurrencyCode = "EGP",
            SupportsMurabaha = true,
            SupportsReceivablesFinance = false,
            SupportsTawarruq = false
        });
        Assert.Equal(HttpStatusCode.OK, partnerResponse.StatusCode);
        var partner = await partnerResponse.Content.ReadFromJsonAsync<IslamicFinancePartnerLenderResponse>();
        Assert.NotNull(partner);

        var submitPartnerResponse = await _client.PostAsync($"/api/v1/islamic-finance/partners/{partner!.Id}/submit", null);
        Assert.Equal(HttpStatusCode.OK, submitPartnerResponse.StatusCode);

        var productResponse = await _client.PostAsJsonAsync("/api/v1/islamic-finance/product-profiles", new CreateIslamicFinanceProductProfileRequest
        {
            ProductType = "MURABAHA",
            ProductCode = "MUR-WB-HTTP-001",
            ProductName = "Murabaha Workbench HTTP Product",
            RequiresShariahReview = true,
            AllowsPartnerFunding = true,
            AllowsCashLineFunding = false
        });
        Assert.Equal(HttpStatusCode.OK, productResponse.StatusCode);
        var product = await productResponse.Content.ReadFromJsonAsync<IslamicFinanceProductProfileResponse>();
        Assert.NotNull(product);

        var requestResponse = await _client.PostAsJsonAsync("/api/v1/islamic-finance/requests", new CreateIslamicFinanceFinancingRequestRequest
        {
            RequestNumber = "IF-REQ-WB-HTTP-001",
            CustomerPartyId = 2,
            ProductProfileId = product!.Id,
            FundingSourceMode = "PARTNER",
            SourceDocumentType = "SALES_ORDER",
            SourceDocumentId = 1,
            TransactionCurrencyCode = "EGP",
            RequestedAmount = 95000m
        });
        Assert.Equal(HttpStatusCode.OK, requestResponse.StatusCode);
        var request = await requestResponse.Content.ReadFromJsonAsync<IslamicFinanceFinancingRequestResponse>();
        Assert.NotNull(request);

        var submitRequestResponse = await _client.PostAsync($"/api/v1/islamic-finance/requests/{request!.Id}/submit", null);
        Assert.Equal(HttpStatusCode.OK, submitRequestResponse.StatusCode);

        var returnRequestResponse = await _client.PostAsync($"/api/v1/islamic-finance/requests/{request.Id}/return", null);
        Assert.Equal(HttpStatusCode.OK, returnRequestResponse.StatusCode);

        var dashboardResponse = await _client.GetAsync("/api/v1/internal/dashboard");
        Assert.Equal(HttpStatusCode.OK, dashboardResponse.StatusCode);
        var dashboard = await dashboardResponse.Content.ReadFromJsonAsync<InternalDashboardSummaryResponse>();
        Assert.NotNull(dashboard);
        Assert.True(dashboard!.FinanceApprovalCount >= 1);
        Assert.True(dashboard.TotalExceptionCount >= 1);

        var approvalsResponse = await _client.GetAsync("/api/v1/internal/work-queues/approvals?moduleCode=FINANCE");
        Assert.Equal(HttpStatusCode.OK, approvalsResponse.StatusCode);
        var approvals = await approvalsResponse.Content.ReadFromJsonAsync<List<InternalApprovalQueueItemResponse>>();
        Assert.NotNull(approvals);
        Assert.Contains(approvals!, item => item.DocumentType == "IF_PARTNER_LENDER" && item.DocumentId == partner.Id);

        var exceptionsResponse = await _client.GetAsync("/api/v1/internal/work-queues/exceptions?sourceType=ISLAMIC_FINANCE");
        Assert.Equal(HttpStatusCode.OK, exceptionsResponse.StatusCode);
        var exceptions = await exceptionsResponse.Content.ReadFromJsonAsync<List<InternalExceptionQueueItemResponse>>();
        Assert.NotNull(exceptions);
        Assert.Contains(exceptions!, item => item.DocumentType == "IF_FINANCING_REQUEST" && item.DocumentId == request.Id && item.CurrentStatus == "RETURNED");
    }
}
