using CashLineERP.Application.Internal;
using CashLineERP.Application.Notifications;
using CashLineERP.Contracts.Notifications;
using CashLineERP.Infrastructure.Persistence.Repositories;

namespace CashLineERP.Api.Tests;

public sealed class NotificationTemplateAndOrchestrationServiceQaTests
{
    [Fact]
    public void Notification_Template_Can_Be_Submitted_Approved_Activated_And_Queued_For_Review()
    {
        using var dbContext = QaDbContextFactory.CreateContext();

        var templateService = new NotificationTemplateService(new NotificationTemplateRepository(dbContext));
        var internalWorkbenchService = new InternalWorkbenchService(new InternalWorkbenchRepository(dbContext));

        var createdTemplate = templateService.CreateTemplate(new CreateNotificationTemplateRequest(
            TemplateName: "Dispatch delivered",
            ChannelCode: "EMAIL",
            SubjectTemplate: "Dispatch {{dispatchNumber}} delivered",
            BodyTemplate: "Dear {{partyName}}, dispatch {{dispatchNumber}} has been delivered.",
            Notes: "Template baseline"));
        Assert.Equal("DRAFT", createdTemplate.StatusCode);

        var submittedTemplate = templateService.SubmitTemplate(createdTemplate.NotificationTemplateId, 2);
        Assert.Equal("SUBMITTED", submittedTemplate.StatusCode);

        var approvalQueue = internalWorkbenchService.GetApprovalQueue("OPERATIONS");
        Assert.Contains(approvalQueue, item => item.DocumentType == "NOTIFICATION_TEMPLATE" && item.DocumentId == createdTemplate.NotificationTemplateId);

        var approvedTemplate = templateService.ApproveTemplate(createdTemplate.NotificationTemplateId, 4);
        Assert.Equal("APPROVED", approvedTemplate.StatusCode);

        var activatedTemplate = templateService.ActivateTemplate(createdTemplate.NotificationTemplateId, 4);
        Assert.True(activatedTemplate.IsActive);
    }

    [Fact]
    public void Notification_Queue_Can_Render_Template_Enqueue_Send_And_Replay()
    {
        using var dbContext = QaDbContextFactory.CreateContext();

        var templateService = new NotificationTemplateService(new NotificationTemplateRepository(dbContext));
        var orchestrationService = new NotificationOrchestrationService(new NotificationOrchestrationRepository(dbContext));

        var template = templateService.CreateTemplate(new CreateNotificationTemplateRequest(
            TemplateName: "Statement ready",
            ChannelCode: "EMAIL",
            SubjectTemplate: "Statement {{statementNumber}} ready",
            BodyTemplate: "Dear {{partyName}}, statement {{statementNumber}} is ready.",
            Notes: "Queue baseline"));
        templateService.SubmitTemplate(template.NotificationTemplateId, 2);
        templateService.ApproveTemplate(template.NotificationTemplateId, 4);
        templateService.ActivateTemplate(template.NotificationTemplateId, 4);

        var queueItem = orchestrationService.EnqueueNotification(2, new EnqueueNotificationRequest(
            NotificationTemplateId: template.NotificationTemplateId,
            RecipientReference: "customer@example.com",
            ContextCode: "STATEMENT",
            RelatedEntityType: "CUSTOMER_STATEMENT",
            RelatedEntityId: 1,
            Variables: new Dictionary<string, string?>
            {
                ["partyName"] = "Shatta Supplies",
                ["statementNumber"] = "CSTMT-000001"
            }));

        Assert.Equal("PENDING", queueItem.StatusCode);
        Assert.Contains("CSTMT-000001", queueItem.Body, StringComparison.Ordinal);

        var deadLettered = orchestrationService.MoveQueueItemToDeadLetter(queueItem.NotificationQueueItemId, 2, new NotificationDeadLetterRequest(
            ReasonText: "SMTP unavailable"));
        Assert.Equal("DEAD_LETTER", deadLettered.StatusCode);

        var replayed = orchestrationService.ReplayQueueItem(deadLettered.NotificationQueueItemId, 2, new NotificationReplayRequest(
            ReplayReasonText: "Retry after mail recovery",
            DelaySeconds: 0));
        Assert.Equal("RETRY", replayed.StatusCode);

        var sendResult = orchestrationService.SendPendingBatch(new NotificationSendBatchRequest(
            SenderCode: "NOTIFICATION_WORKER",
            BatchSize: 10));
        var sentItem = Assert.Single(sendResult.SentItems, item => item.NotificationQueueItemId == queueItem.NotificationQueueItemId);
        Assert.Equal("SENT", sentItem.StatusCode);
        Assert.Equal("NOTIFICATION_WORKER", sentItem.SentByProcess);
    }
}
