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

namespace CashLineERP.Api.Tests;

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

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

    [Fact]
    public async Task Eta_Endpoints_Return_Preview_Validation_Submit_Response_And_Event_History()
    {
        long invoiceId;

        using (var scope = _factory.Services.CreateScope())
        {
            var invoiceService = scope.ServiceProvider.GetRequiredService<IAccountsReceivableInvoiceService>();

            var invoice = invoiceService.CreateInvoice(new CreateAccountsReceivableInvoiceRequest(
                CustomerId: 2,
                SalesOrderId: 1,
                DispatchOrderId: 1,
                InvoiceType: "TAX",
                InvoiceDate: new DateOnly(2026, 5, 31),
                TaxDate: new DateOnly(2026, 5, 31),
                DueDate: new DateOnly(2026, 6, 10),
                CurrencyCode: "EGP",
                Lines:
                [
                    new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 2m, "EA", 32m, "VAT14")
                ]));

            invoiceId = AccountsReceivableWorkflowTestHelper
                .SubmitApproveAndPostInvoice(invoiceService, invoice.AccountsReceivableInvoiceId)
                .AccountsReceivableInvoiceId;
        }

        await _client.AuthenticateAsFinanceMakerAsync();

        var previewResponse = await _client.GetAsync($"/api/v1/finance/ar-invoices/{invoiceId}/eta-payload-preview");
        Assert.Equal(HttpStatusCode.OK, previewResponse.StatusCode);
        var preview = await previewResponse.Content.ReadFromJsonAsync<EtaPayloadPreviewResponse>();
        Assert.NotNull(preview);
        Assert.True(preview!.IsStatutoryReady);
        Assert.Equal("TAX_INVOICE", preview.NormalizedDocumentType);

        var validationPackResponse = await _client.GetAsync($"/api/v1/finance/ar-invoices/{invoiceId}/eta-validation-pack");
        Assert.Equal(HttpStatusCode.OK, validationPackResponse.StatusCode);
        var validationPack = await validationPackResponse.Content.ReadFromJsonAsync<EtaSubmissionValidationPackResponse>();
        Assert.NotNull(validationPack);
        Assert.True(validationPack!.IsValid);
        Assert.Contains(validationPack.Rules, rule => rule.RuleGroup == "BRANCH" && rule.IsSatisfied);
        Assert.Contains(validationPack.Rules, rule => rule.RuleGroup == "BUYER" && rule.IsSatisfied);

        var submitResponse = await _client.PostAsJsonAsync(
            $"/api/v1/finance/ar-invoices/{invoiceId}/eta-submit",
            new SubmitInvoiceToEtaRequest(ActorUserId: 0, PayloadText: null));
        Assert.Equal(HttpStatusCode.OK, submitResponse.StatusCode);
        var submission = await submitResponse.Content.ReadFromJsonAsync<EtaSubmissionLogResponse>();
        Assert.NotNull(submission);
        Assert.Equal("SUBMITTED", submission!.StatusCode);
        Assert.NotNull(submission.SubmissionReference);

        var recordResponse = await _client.PostAsJsonAsync(
            $"/api/v1/finance/ar-invoices/{invoiceId}/eta-submissions/{submission.EtaSubmissionLogId}/response",
            new RecordEtaInvoiceResponseRequest(
                ActorUserId: 0,
                StatusCode: "ACCEPTED",
                EtaUuid: "ETA-HTTP-000001",
                ResponseText: "{\"status\":\"accepted\"}",
                ErrorCode: null,
                ErrorMessage: null,
                NotesText: "HTTP ETA acceptance"));
        Assert.Equal(HttpStatusCode.OK, recordResponse.StatusCode);
        var accepted = await recordResponse.Content.ReadFromJsonAsync<EtaSubmissionLogResponse>();
        Assert.NotNull(accepted);
        Assert.Equal("ACCEPTED", accepted!.StatusCode);
        Assert.Equal("ETA-HTTP-000001", accepted.EtaUuid);

        var logsResponse = await _client.GetAsync($"/api/v1/finance/ar-invoices/{invoiceId}/eta-submissions");
        Assert.Equal(HttpStatusCode.OK, logsResponse.StatusCode);
        var logs = await logsResponse.Content.ReadFromJsonAsync<List<EtaSubmissionLogResponse>>();
        Assert.NotNull(logs);
        Assert.Contains(logs!, item => item.EtaSubmissionLogId == submission.EtaSubmissionLogId && item.StatusCode == "ACCEPTED");

        var eventsResponse = await _client.GetAsync($"/api/v1/finance/ar-invoices/{invoiceId}/eta-events");
        Assert.Equal(HttpStatusCode.OK, eventsResponse.StatusCode);
        var events = await eventsResponse.Content.ReadFromJsonAsync<List<EtaDocumentEventResponse>>();
        Assert.NotNull(events);
        Assert.Contains(events!, item => item.EventType == "SUBMISSION" && item.EventStatus == "SUBMITTED");
        Assert.Contains(events, item => item.EventType == "RESPONSE" && item.EventStatus == "ACCEPTED");
    }

    [Fact]
    public async Task Eta_Rejected_Submission_Can_Be_Resubmitted_Through_Http_Endpoints()
    {
        long invoiceId;

        using (var scope = _factory.Services.CreateScope())
        {
            var invoiceService = scope.ServiceProvider.GetRequiredService<IAccountsReceivableInvoiceService>();

            var invoice = invoiceService.CreateInvoice(new CreateAccountsReceivableInvoiceRequest(
                CustomerId: 2,
                SalesOrderId: 1,
                DispatchOrderId: 1,
                InvoiceType: "TAX",
                InvoiceDate: new DateOnly(2026, 5, 30),
                TaxDate: new DateOnly(2026, 5, 30),
                DueDate: new DateOnly(2026, 6, 9),
                CurrencyCode: "EGP",
                Lines:
                [
                    new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 3m, "EA", 32m, "VAT14")
                ]));

            invoiceId = AccountsReceivableWorkflowTestHelper
                .SubmitApproveAndPostInvoice(invoiceService, invoice.AccountsReceivableInvoiceId)
                .AccountsReceivableInvoiceId;
        }

        await _client.AuthenticateAsFinanceMakerAsync();

        var submitResponse = await _client.PostAsJsonAsync(
            $"/api/v1/finance/ar-invoices/{invoiceId}/eta-submit",
            new SubmitInvoiceToEtaRequest(ActorUserId: 0, PayloadText: null));
        Assert.Equal(HttpStatusCode.OK, submitResponse.StatusCode);
        var submission = await submitResponse.Content.ReadFromJsonAsync<EtaSubmissionLogResponse>();
        Assert.NotNull(submission);

        var rejectResponse = await _client.PostAsJsonAsync(
            $"/api/v1/finance/ar-invoices/{invoiceId}/eta-submissions/{submission!.EtaSubmissionLogId}/response",
            new RecordEtaInvoiceResponseRequest(
                ActorUserId: 0,
                StatusCode: "REJECTED",
                EtaUuid: null,
                ResponseText: "{\"status\":\"rejected\"}",
                ErrorCode: "ETA-001",
                ErrorMessage: "Rejected for correction",
                NotesText: "Rejected in HTTP lifecycle"));
        Assert.Equal(HttpStatusCode.OK, rejectResponse.StatusCode);

        var resubmitResponse = await _client.PostAsJsonAsync(
            $"/api/v1/finance/ar-invoices/{invoiceId}/eta-submissions/{submission.EtaSubmissionLogId}/resubmit",
            new ResubmitEtaInvoiceRequest(
                ActorUserId: 0,
                PayloadText: null,
                CorrectionNotes: "Corrected and resubmitted via HTTP"));
        Assert.Equal(HttpStatusCode.OK, resubmitResponse.StatusCode);
        var resubmission = await resubmitResponse.Content.ReadFromJsonAsync<EtaSubmissionLogResponse>();
        Assert.NotNull(resubmission);
        Assert.Equal("SUBMITTED", resubmission!.StatusCode);
        Assert.NotEqual(submission.EtaSubmissionLogId, resubmission.EtaSubmissionLogId);

        var eventsResponse = await _client.GetAsync($"/api/v1/finance/ar-invoices/{invoiceId}/eta-events");
        Assert.Equal(HttpStatusCode.OK, eventsResponse.StatusCode);
        var events = await eventsResponse.Content.ReadFromJsonAsync<List<EtaDocumentEventResponse>>();
        Assert.NotNull(events);
        Assert.Contains(events!, item => item.EventType == "CORRECTION" && item.EventStatus == "PREPARED");
        Assert.Contains(events, item => item.EventType == "RESUBMISSION" && item.EventStatus == "SUBMITTED");
    }
}
