using CashLineERP.Application.Notifications;
using CashLineERP.Domain.Notifications;
using CashLineERP.Domain.Workflow;
using CashLineERP.SharedKernel.Workflow;
using Microsoft.EntityFrameworkCore;

namespace CashLineERP.Infrastructure.Persistence.Repositories;

public sealed class NotificationTemplateRepository : INotificationTemplateRepository
{
    private readonly CashLineErpDbContext _dbContext;

    public NotificationTemplateRepository(CashLineErpDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IReadOnlyCollection<NotificationTemplateDetailView> GetTemplates(bool activeOnly = false, string? channelCode = null)
    {
        var normalizedChannelCode = string.IsNullOrWhiteSpace(channelCode) ? null : channelCode.Trim().ToUpperInvariant();

        return _dbContext.NotificationTemplates
            .AsNoTracking()
            .Where(entry => !activeOnly || entry.IsActive)
            .Where(entry => normalizedChannelCode == null || entry.ChannelCode == normalizedChannelCode)
            .OrderBy(entry => entry.ChannelCode)
            .ThenBy(entry => entry.TemplateCode)
            .ToArray()
            .Select(Map)
            .ToArray();
    }

    public NotificationTemplateDetailView? GetTemplate(long notificationTemplateId)
    {
        var template = _dbContext.NotificationTemplates
            .AsNoTracking()
            .SingleOrDefault(entry => entry.Id == notificationTemplateId);

        return template is null ? null : Map(template);
    }

    public NotificationTemplateDetailView Create(CreateNotificationTemplateCommand command)
    {
        var nextSequence = (_dbContext.NotificationTemplates.Max(entry => (long?)entry.Id) ?? 0L) + 1L;
        var normalizedChannelCode = command.ChannelCode.Trim().ToUpperInvariant();

        var template = new NotificationTemplate(
            templateCode: $"NTTMP-{nextSequence:D6}",
            templateName: command.TemplateName,
            channelCode: normalizedChannelCode,
            subjectTemplate: command.SubjectTemplate,
            bodyTemplate: command.BodyTemplate,
            notes: command.Notes);

        _dbContext.NotificationTemplates.Add(template);
        _dbContext.SaveChanges();
        return GetTemplate(template.Id)!;
    }

    public NotificationTemplateDetailView Submit(long notificationTemplateId, long actorUserId)
    {
        var template = _dbContext.NotificationTemplates.Single(entry => entry.Id == notificationTemplateId);
        template.Submit(actorUserId);

        var workflowInstance = new WorkflowInstance(
            moduleCode: "OPERATIONS",
            documentType: "NOTIFICATION_TEMPLATE",
            documentId: template.Id,
            makerUserId: actorUserId,
            workflowRuleId: 1L);
        workflowInstance.Submit(actorUserId, "Notification template submitted for approval.");

        _dbContext.WorkflowInstances.Add(workflowInstance);
        _dbContext.SaveChanges();
        return GetTemplate(template.Id)!;
    }

    public NotificationTemplateDetailView Approve(long notificationTemplateId, long actorUserId)
    {
        var template = _dbContext.NotificationTemplates.Single(entry => entry.Id == notificationTemplateId);
        template.Approve(actorUserId);

        var workflowInstance = _dbContext.WorkflowInstances
            .Include(entry => entry.Actions)
            .SingleOrDefault(entry => entry.DocumentType == "NOTIFICATION_TEMPLATE" && entry.DocumentId == notificationTemplateId);
        workflowInstance?.Approve(actorUserId, "Notification template approved.");

        _dbContext.SaveChanges();
        return GetTemplate(template.Id)!;
    }

    public NotificationTemplateDetailView Activate(long notificationTemplateId, long actorUserId)
    {
        var template = _dbContext.NotificationTemplates.Single(entry => entry.Id == notificationTemplateId);
        template.Activate(actorUserId);
        _dbContext.SaveChanges();
        return GetTemplate(template.Id)!;
    }

    private static NotificationTemplateDetailView Map(NotificationTemplate template) =>
        new(
            template.Id,
            template.TemplateCode,
            template.TemplateName,
            template.ChannelCode,
            template.SubjectTemplate,
            template.BodyTemplate,
            WorkflowStatusSeedIds.ToCode(template.StatusId),
            template.IsActive,
            template.Notes,
            template.SubmittedAtUtc,
            template.SubmittedByUserId,
            template.ApprovedAtUtc,
            template.ApprovedByUserId,
            template.ActivatedAtUtc,
            template.ActivatedByUserId);
}
