using System.Net.Mail;
using IWS5.Core.Enums;
using IWS5.Core.Models;
using IWS5.Core.Models.Processing;
using IWS5.Server.Utils;
using Microsoft.Data.SqlClient;
using ILogger = Serilog.ILogger;
using IWS5.Core.Helpers;
using IWS5.DatabaseAccess.Interfaces;

namespace IWS5.Server.EventProcessors;

public class MailProcessor(ILogger logger, 
    IConfiguration configuration, 
    IMessageProcessor messageProcessor, 
    IWorkItemReferenceRepository workItemReferenceRepository,
    IMailRepository mailRepository, 
    IConnectionRepository connectionRepository) : EventProcessor(logger, configuration)
{
    public override async Task<bool> ProcessEventAsync(EventModel eventData, int processId)
    {
        Logger.Information(
            "Starting mail event processing for WorkItemId: {WorkItemId}, EventId: {EventId}, ProcessId: {ProcessId}",
            eventData.WorkItemId, eventData.CurrentEventId, processId);

        try
        {
            using (var sqlConnection = new SqlConnection(ConnectionString))
            {
                await sqlConnection.OpenAsync();
                Logger.Debug("Database connection opened for mail processing");

                Logger.Debug("Retrieving mail configuration for ProcessId: {ProcessId}, EventId: {EventId}",
                    eventData.CurrentProcessId, eventData.CurrentEventId);

                //Get the Mail record for the ProcessId and the EventId
                var mailInstance = await mailRepository.FindAsync(atMail => atMail.ProcessId == eventData.CurrentProcessId && atMail.EventId == eventData.CurrentEventId);

                if (mailInstance is null)
                {
                    Logger.Warning("No mail configuration found for ProcessId: {ProcessId}, EventId: {EventId}",
                        eventData.CurrentProcessId, eventData.CurrentEventId);
                    return false;
                }

                Logger.Debug("Found mail configuration record");

                var mailTask = new MailTask()
                {
                    ServerId = mailInstance.ConnectionId.Value,
                    Recipients = mailInstance.Recipient.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries),
                    From = mailInstance.From,
                    ReplyTo = mailInstance.Reply,
                    CC = mailInstance.Cc.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries),
                    BCC = mailInstance.Bcc.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries),
                    Subject = mailInstance.Subject,
                    Message = mailInstance.Message,
                    Enabled = mailInstance.Enable,
                    Priority = (MailPriority)Enum.Parse(typeof(MailPriority), mailInstance.Priority.ToString()),
                };

                Logger.Debug(
                    "Mail task configuration - ServerId: {ServerId}, Recipients: {RecipientCount}, From: {From}, Priority: {Priority}, Enabled: {Enabled}",
                    mailTask.ServerId, mailTask.Recipients?.Length ?? 0, mailTask.From, mailTask.Priority,
                    mailTask.Enabled);

                Logger.Debug("Processing message templates for Subject and Message");
                mailTask.Subject = await messageProcessor.ProcessMessage(new MessageModel { 
                    Message = mailTask.Subject,
                    WorkItemId = eventData.WorkItemId,
                    SourceUser = eventData.SourceUser,
                    SourceQueueId = eventData.SourceQueueId ?? 0,
                    EventId = eventData.CurrentEventId,
                    LastAction = eventData.LastAction
                });
                
                mailTask.Message = await messageProcessor.ProcessMessage(new MessageModel {
                    Message = mailTask.Message,
                    WorkItemId = eventData.WorkItemId,
                    SourceUser = eventData.SourceUser,
                    SourceQueueId = eventData.SourceQueueId ?? 0,
                    EventId = eventData.CurrentEventId,
                    LastAction = eventData.LastAction
                });

                var recipientsString = await messageProcessor.ProcessMessage(new MessageModel
                {
                    Message = string.Join(";", mailTask.Recipients),
                    WorkItemId = eventData.WorkItemId,
                    SourceUser = eventData.SourceUser,
                    SourceQueueId = eventData.SourceQueueId ?? 0,
                    EventId = eventData.CurrentEventId,
                    LastAction = eventData.LastAction
                });
                
                mailTask.Recipients = recipientsString
                    .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
                    .Select(email => email.Trim())
                    .Where(email => IsValidEmail(email))
                    .ToArray();

                Logger.Debug("Processed message templates - Subject: {Subject}, MessageLength: {MessageLength}",
                    mailTask.Subject, mailTask.Message?.Length ?? 0);

                if (mailTask.Enabled)
                {
                    Logger.Debug("Retrieving mail server configuration for ConnectionId: {ConnectionId}",
                    mailTask.ServerId);

                    var connection = await connectionRepository.FindAsync(atConn => atConn.Id == mailTask.ServerId);
                    
                    if (connection is null)
                    {
                        Logger.Error(
                            "Mail server configuration not found for ConnectionId: {ConnectionId}, WorkItemId: {WorkItemId}",
                            mailTask.ServerId, eventData.WorkItemId);
                        return false;
                    }

                    Logger.Debug(
                        "Retrieved mail server configuration - UserName: {UserName}, ConnectionString: {ConnectionStringLength} chars",
                        connection.UserName, connection.ConnectionString?.Length ?? 0);

                    Logger.Information("Sending email for WorkItemId: {WorkItemId} to {RecipientCount} recipient(s)",
                        eventData.WorkItemId, mailTask.Recipients?.Length ?? 0);

                    var result = MailSender.SendEmail(mailTask, connection.ConnectionString, connection.UserName, connection.Password);

                    if (result)
                    {
                        Logger.Information(
                            "Email sent successfully for WorkItemId: {WorkItemId}",
                            eventData.WorkItemId, eventData.NextEventId);
                    }
                    else
                    {
                        Logger.Error("Failed to send email for WorkItemId: {WorkItemId}", eventData.WorkItemId);
                    }
                } else
                {
                    Logger.Information("Mail task is disabled, skipping email send for WorkItemId: {WorkItemId}",
                        eventData.WorkItemId);
                }

                Logger.Information("Updating work item reference to NextEventId: {NextEventId}",
                    eventData.WorkItemId, eventData.NextEventId);
                
                ForwardWorkItemServerRequest forwardWorkItemServerRequest = new ForwardWorkItemServerRequest
                {
                    WorkItemId = eventData.WorkItemId,
                    EventId = eventData.NextEventId,
                    PendEventId = 0,
                    PendingQueueId = null,
                    ServerRequest = ServerRequest.ForwardExistingWorkItem,
                    ServerRequestParam = null,
                    LastActionDate = DateTime.Now
                };
                
                logger.Information("WorkItemId: {WorkItemId} - Forwarding work item from EventId: {CurrentEventId} to NextEventId: {NextEventId}",
                    eventData.WorkItemId, eventData.CurrentEventId, eventData.NextEventId);
        
                await workItemReferenceRepository.ForwardWorkItemAsync(forwardWorkItemServerRequest);
                Logger.Debug("Work item reference updated successfully");
                return true;
            }
        }
        catch (Exception ex)
        {
            Logger.Error(ex, "Error processing mail event for WorkItemId: {WorkItemId}, EventId: {EventId}",
                eventData.WorkItemId, eventData.CurrentEventId);
            return false;
        }
    }
    
    private static bool IsValidEmail(string email)
    {
        if (string.IsNullOrWhiteSpace(email))
            return false;

        try
        {
            var addr = new System.Net.Mail.MailAddress(email);
            return addr.Address == email.Trim();
        }
        catch
        {
            return false;
        }
    }
}