Imports DigitalData.Modules.Base
Imports DigitalData.Modules.Logging
Imports Limilabs.Client.SMTP
Namespace Mail
    Public Class MailSender
        Inherits BaseClass

        Public Property MailSession As MailSession

        Public ReadOnly Property Connected2Server As Boolean
            Get
                If MailSession IsNot Nothing AndAlso MailSession.Session IsNot Nothing Then

                    Return MailSession.Session.Connected
                Else
                    Return False
                End If
            End Get
        End Property

        Public Sub New(pLogConfig As LogConfig)
            MyBase.New(pLogConfig)
            MailSession = New MailSession(pLogConfig, New Smtp)
            Limilabs.Mail.Log.Enabled = pLogConfig.Debug
        End Sub

        Public Function Connect(pServer As String, pPort As Integer, pUser As String, pPassword As String, pAuthType As String) As MailSession.SessionInfo
            Return MailSession.ConnectToServerWithBasicAuth(pServer, pPort, pUser, pPassword, pAuthType, New MailSession.MailSessionOptions)
        End Function

        Public Function Connect(pServer As String, pPort As Integer, pUser As String, pPassword As String, pAuthType As String, pOptions As MailSession.MailSessionOptions) As MailSession.SessionInfo
            Return MailSession.ConnectToServerWithBasicAuth(pServer, pPort, pUser, pPassword, pAuthType, pOptions)
        End Function
        Public Function ConnectToO365(pUser As String, pClientId As String, pTenantId As String, pClientSecret As String) As MailSession.SessionInfo
            Dim oOptions = New MailSession.MailSessionOptions With {.EnableTls1_2 = True}
            Return MailSession.ConnectToServerWithO365OAuth(pUser, pClientId, pTenantId, pClientSecret, oOptions)
        End Function
        Public Function Disconnect() As Boolean
            Return MailSession.DisconnectFromServer()
        End Function

        Public Function SendMail(pSendTo As List(Of String), pSendFrom As String, pSubject As String, pBody As String, pCreationTime As Date, pAttachments As List(Of String), pTest As Boolean) As Boolean
            Try
                Dim oSuccessfulSends As New List(Of String)
                Dim oFailedSends As New List(Of String)
                Dim oResult As Boolean
                For Each oSendToAddress In pSendTo

                    If IsValidEmailAddress(oSendToAddress) Then
                        oResult = SendMailTo(oSendToAddress, pSendFrom, pSubject, pBody, pCreationTime, pAttachments, pTest)
                    Else
                        Logger.Warn("EMail adress [{0}] is NOT valid!", oSendToAddress)
                        oResult = False
                    End If

                    If oResult = True Then
                        oSuccessfulSends.Add(oSendToAddress & "|" & pSubject)
                    Else
                        oFailedSends.Add(oSendToAddress & "|" & pSubject)
                    End If
                Next

                Logger.Debug("Sent [{0}] mails.", pSendTo.Count)
                Logger.Debug("Successful [{0}]", oSuccessfulSends.Count)
                Logger.Debug("Failed [{0}]", oFailedSends.Count)
                If oFailedSends.Count > 0 Then
                    Return False
                Else
                    Return True
                End If
            Catch ex As Exception
                Logger.Warn("Error in SendMail()  - while sending mail [{0} - Subject: {1}]", pSendTo, pSubject)
                Logger.Error(ex)

                Return False
            End Try

        End Function

        Private Function SendMailTo(pSendTo As String, pSendFrom As String, pSubject As String, pBody As String, pCreationTime As Date, pAttachments As List(Of String), pTest As Boolean)
            Try
                Dim oClient As Smtp = DirectCast(MailSession.Client, Smtp)

                If IsNothing(oClient) Then
                    Logger.Warn("Client is nothing! Exiting.")
                    Return False
                End If

                Logger.Debug("Preparing to send mail: {0} ...", pSendTo + "|" + pSubject)

                Dim oMailBuilder As New Limilabs.Mail.MailBuilder()
                oMailBuilder.From.Add(New Limilabs.Mail.Headers.MailBox(pSendFrom))
                oMailBuilder.To.Add(New Limilabs.Mail.Headers.MailBox(pSendTo))
                oMailBuilder.Subject = pSubject

                Logger.Debug("Setting body for mail")
                oMailBuilder = SetBody(oMailBuilder, pBody, pCreationTime, pTest)

                Logger.Debug("Adding [{0}] attachments to mail", pAttachments.Count)
                oMailBuilder = AddAttachments(oMailBuilder, pAttachments)

                Logger.Debug("Now sending mail...")
                Dim oMail = oMailBuilder.Create()
                oClient.SendMessage(oMail)
                Logger.Info("Mail [{0}] has been sent.", pSendTo + "|" + pSubject)

                Return True

            Catch ex As Exception
                Logger.Warn("Error in SendMailTo() - Mailinfo: {0} - Subject: {1}", pSendTo, pSubject)
                Logger.Error(ex)
                MailSession.DisconnectFromServer()

                Return False
            End Try
        End Function

        Private Function SetBody(pMailBuilder As Limilabs.Mail.MailBuilder, pBody As String, pCreationTime As Date, pTest As Boolean) As Limilabs.Mail.MailBuilder
            If pCreationTime <> Date.MinValue Then
                pBody &= $"<p><i>{pCreationTime}</i></p>"
            End If

            If pTest Then
                pBody = $"<p>This Is a Testmail!<br/>
                            The body-text will be replaced within profile!<br/>
                            Server/Port: {MailSession.Session.Server}/{MailSession.Session.Port}<br/> 
                            User: {MailSession.Session.User}<br/>
                            Password: XXXX<br/>
                            Auth Type: {MailSession.Session.AuthType}</p>"
            End If

            Logger.Debug("Final Mailbody is: [{0}]", pBody)
            pMailBuilder.Html = pBody

            Return pMailBuilder
        End Function

        Private Function AddAttachments(pMailBuilder As Limilabs.Mail.MailBuilder, pAttachments As List(Of String)) As Limilabs.Mail.MailBuilder
            For Each oAttachment In pAttachments
                Try
                    If oAttachment <> String.Empty Then
                        ' Read attachment from disk, add it to Attachments collection
                        If IO.File.Exists(oAttachment) Then
                            Logger.Debug("Adding attachment [{0}] to mail.", oAttachment)
                            pMailBuilder.AddAttachment(oAttachment)
                        Else
                            Logger.Warn("Attachment [{0}] does not exist. Skipping.", oAttachment)
                        End If
                    Else
                        Logger.Debug("Attachment is String.Empty")
                    End If

                Catch ex As Exception
                    Logger.Warn("Could not read or add attachment [{0}]!", oAttachment)
                    Logger.Error(ex)
                End Try
            Next

            Return pMailBuilder
        End Function

        Private Function IsValidEmailAddress(pEmailAddress As String) As Boolean
            Try
                If pEmailAddress.Contains("@") Then
                    Dim oAddress = New System.Net.Mail.MailAddress(pEmailAddress)
                    Return oAddress.Address = pEmailAddress
                Else
                    Return False
                End If
            Catch ex As Exception
                Return False
            End Try
        End Function
    End Class
End Namespace

