Imports DigitalData.Modules.Base
Imports DigitalData.Modules.Logging
Imports Limilabs.Client.IMAP
Imports Limilabs.Client
Imports Limilabs.Mail

Namespace Mail
    Public Class MailFetcher
        Inherits BaseClass
        Private MailSession As MailSession
        Private ReadOnly MailBuilder As New MailBuilder

        Public ReadOnly Property Connected2Server As Boolean
            Get
                Return MailSession.Session.Connected
            End Get
        End Property

        Public ReadOnly Property Client As Imap
            Get
                Return MailSession?.Client
            End Get
        End Property

        Public Sub New(pLogConfig As LogConfig)
            MyBase.New(pLogConfig)
            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
            MailSession = New MailSession(LogConfig, New Imap)

            Return MailSession.ConnectToServerWithBasicAuth(pServer, pPort, pUser, pPassword, pAuthType, New MailSession.MailSessionOptions)
        End Function

        Public Function ConnectToO365(pUser As String, pClientId As String, pTenantId As String, pClientSecret As String)
            MailSession = New MailSession(LogConfig, New Imap)

            Dim oOptions = New MailSession.MailSessionOptions With {.EnableTls1_2 = True}
            Return MailSession.ConnectToServerWithO365OAuth(pUser, pClientId, pTenantId, pClientSecret, oOptions)
        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
            MailSession = New MailSession(LogConfig, New Imap)

            Return MailSession.ConnectToServerWithBasicAuth(pServer, pPort, pUser, pPassword, pAuthType, pOptions)
        End Function

        Public Function Disconnect() As Boolean
            If (MailSession.Session.Connected = False) Then
                Return True
            End If

            Return MailSession.DisconnectFromServer()
        End Function

        Public Async Function FetchAllMailsAsync() As Task(Of List(Of IMail))
            Return Await FetchMailsAsync(Flag.All)
        End Function

        Public Async Function FetchUnreadMailsAsync() As Task(Of List(Of IMail))
            Return Await FetchMailsAsync(Flag.Unseen)
        End Function
        Public Function FetchAllMails() As List(Of IMail)
            Return FetchMails(Flag.All)
        End Function

        Public Function FetchUnreadMails() As List(Of IMail)
            Return FetchMails(Flag.Unseen)
        End Function

        Public Function ListAllMails() As List(Of Long)
            Return ListMails(Flag.All)
        End Function

        Public Function ListUnseenMails() As List(Of Long)
            Return ListMails(Flag.Unseen)
        End Function

        Public Function FetchMails(pMailFlag As Flag) As List(Of IMail)
            Try
                If MailSession.Session.Connected Then
                    Dim oMailIds = ListMails(pMailFlag)
                    Dim oMails As New List(Of IMail)

                    For Each oId In oMailIds

                        Dim oMail As IMail = FetchMail(oId)
                        oMails.Add(oMail)

                    Next

                    Return oMails
                Else
                    Logger.Error("No connection to Server. Exiting.")
                    Return Nothing
                End If
            Catch ex As Exception
                Logger.Error(ex)
                Return Nothing
            End Try

        End Function

        Public Async Function FetchMailsAsync(pMailFlag As Flag) As Task(Of List(Of IMail))
            Try
                If MailSession.Session.Connected Then
                    Dim oMailIds = ListMails(pMailFlag)
                    Dim oMails As New List(Of IMail)

                    For Each oId In oMailIds

                        Dim oMail As IMail = Await FetchMailAsync(oId)
                        oMails.Add(oMail)

                    Next

                    Return oMails
                Else
                    Logger.Error("No connection to Server. Exiting.")
                    Return Nothing
                End If
            Catch ex As Exception
                Logger.Error(ex)
                Return Nothing
            End Try

        End Function

        Public Function ListMails(pMailFlag As Flag) As List(Of Long)
            Try
                If MailSession.Session.Connected Then
                    Dim oClient As Imap = MailSession.Client
                    Dim oStatus = oClient.SelectInbox()

                    Dim oMailIds = oClient.Search(pMailFlag)
                    Logger.Debug("Fetched [{0}] mail objects.", oMailIds.Count)

                    Return oMailIds
                Else
                    Logger.Error("No connection to Server. Exiting.")
                    Return Nothing
                End If
            Catch ex As Exception
                Logger.Error(ex)
                Return Nothing
            End Try
        End Function

        Public Async Function ListMailsAsync(pMailFlag As Flag) As Task(Of List(Of Long))
            Try
                If MailSession.Session.Connected Then
                    Dim oClient As Imap = MailSession.Client
                    Dim oStatus = Await oClient.SelectInboxAsync()

                    Dim oMailIds = Await oClient.SearchAsync(pMailFlag)
                    Logger.Debug("Fetched [{0}] mail objects.", oMailIds.Count)

                    Return oMailIds
                Else
                    Logger.Error("No connection to Server. Exiting.")
                    Return Nothing
                End If
            Catch ex As Exception
                Logger.Error(ex)
                Return Nothing
            End Try
        End Function

        Public Function FetchMail(pMailId As Long) As IMail
            Try
                If MailSession.Session.Connected Then
                    Dim oClient As Imap = MailSession.Client

                    Logger.Debug("Fetching mail with Id [{0}]", pMailId)

                    Dim oBuffer As Byte() = oClient.GetMessageByUID(pMailId)
                    Dim oMail As IMail = MailBuilder.CreateFromEml(oBuffer)

                    Return oMail
                Else
                    Logger.Error("No connection to Server. Exiting.")
                    Return Nothing
                End If
            Catch ex As Exception
                Logger.Error(ex)
                Return Nothing
            End Try
        End Function

        Public Async Function FetchMailAsync(pMailId As Long) As Task(Of IMail)
            Try
                If MailSession.Session.Connected Then
                    Dim oClient As Imap = MailSession.Client

                    Logger.Debug("Fetching mail with Id [{0}]", pMailId)

                    Dim oBuffer As Byte() = Await oClient.GetMessageByUIDAsync(pMailId)
                    Dim oMail As IMail = MailBuilder.CreateFromEml(oBuffer)

                    Return oMail
                Else
                    Logger.Error("No connection to Server. Exiting.")
                    Return Nothing
                End If
            Catch ex As Exception
                Logger.Error(ex)
                Return Nothing
            End Try
        End Function

        Public Function DeleteMail(pMailId As Long) As Boolean
            Try
                If MailSession.Session.Connected Then
                    Dim oClient As Imap = MailSession.Client

                    Logger.Debug("Fetching mail with Id [{0}]", pMailId)

                    oClient.DeleteMessageByUID(pMailId)

                    Return True
                Else
                    Logger.Error("No connection to Server. Exiting.")
                    Return False
                End If
            Catch ex As Exception
                Logger.Error(ex)
                Return False
            End Try
        End Function
    End Class
End Namespace

