Imports System.IO
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Patterns
Imports DigitalData.Modules.Language
Imports DigitalData.Services.EDMIService.Methods.Database
Imports DigitalData.Services.EDMIService.Methods.IDB
Imports DigitalData.Modules.ZooFlow.State

Namespace Methods.GlobalIndexer.ImportFile
    Public Class ImportFileMethod
        Inherits BaseMethod

        Private ReadOnly Loader As Loader
        Private ReadOnly Patterns As Patterns2
        Private ReadOnly GetDatatable As GetDatatableFromCache.GetDatatableFromCacheMethod
        Private ReadOnly Connection As SqlClient.SqlConnection
        Private ReadOnly Transaction As SqlClient.SqlTransaction

        Private User As UserState

        Public Sub New(pLogConfig As LogConfig, pDatabaseIDB As MSSQLServer, pDatabaseECM As MSSQLServer, pGlobalState As GlobalState)
            MyBase.New(pLogConfig, pDatabaseIDB, pDatabaseECM, pGlobalState)

            Patterns = New Patterns2(pLogConfig)
            Loader = New Loader(pLogConfig, DatabaseIDB, pDatabaseECM, pGlobalState)
            Connection = DatabaseIDB.GetConnection()
            Transaction = Connection.BeginTransaction()
        End Sub

        ''' <summary>
        ''' 
        ''' </summary>
        ''' <remarks>
        ''' 
        ''' 
        ''' 
        ''' </remarks>
        Public Function Run(pData As ImportFileRequest)
            Try
                User = pData.User

                ' TODO: Add missing user properties in UserState from TBDD_USER
                'pData.User = ResolveUserFromUserName(pData.User.UserName)

                Dim oManualIndexes = Loader.LoadManualIndexes(pData.ProfileId)
                Dim oAutomaticIndexes = Loader.LoadAutomaticIndexes(pData.ProfileId)
                Dim oPostProcessingSteps = Loader.LoadPostProcessingSteps(oManualIndexes)
                Dim oProfile = Loader.LoadProfile(pData.ProfileId)

                Dim oUserAttributes = pData.AttributeValues
                Dim oAutoAttributes As List(Of UserAttributeValue) = Nothing

                ' Apply post processing
                Dim oPostProcessing = New Steps.PostProcessing(LogConfig, oPostProcessingSteps)
                oUserAttributes = oPostProcessing.ApplyManualPostprocessing(oUserAttributes)

                ' Apply automatic attributes
                Dim oAutomaticIndexing = New Steps.AutomaticIndexing(LogConfig, DatabaseIDB, oAutomaticIndexes, GlobalState)
                oAutoAttributes = oAutomaticIndexing.ApplyAutomaticeAttributes(oUserAttributes, pData.File.FileInfoRaw, User)

                ' Import the file
                Dim oNewFile As New NewFile.NewFileMethod(LogConfig, DatabaseIDB, DatabaseECM, GlobalState)
                Dim oResponse = oNewFile.Run(New NewFile.NewFileRequest With {
                    .File = pData.File,
                    .BusinessEntity = pData.BusinessEntity,
                    .KindType = pData.KindType,
                    .StoreName = pData.StoreName,
                    .User = User
                })

                If oResponse.OK Then
                    Logger.Info("Import of file [{0}] under ObjectId [{1}] successful!", pData.File.FileName, oResponse.ObjectId)
                Else
                    Throw New ApplicationException(oResponse.ErrorMessage)
                End If

                ' Generate display Filename from nameconvention
                Dim oDisplayFilename = GetFilenameByNameconvention(
                    pData.File.FileInfoRaw, oProfile.NameConvention, User, oUserAttributes, oAutoAttributes)

                ' Generate virtual path from profile
                Dim oDynamicFilePath = GetVirtualPath(
                    pData.File.FileInfoRaw, oProfile.DynamicPath, User, oUserAttributes, oAutoAttributes)

                Logger.Info("Collecting Attributes for ObjectId [{0}]", oResponse.ObjectId)

                Dim oFinalAttributes As New Dictionary(Of String, List(Of String)) From {
                    {"DisplayFileName", New List(Of String) From {oDisplayFilename}},
                    {"Dynamic Folder", New List(Of String) From {oDynamicFilePath}}
                }
                oFinalAttributes = oFinalAttributes.
                    Concat(Helpers.UserAttributesToDictionary(oUserAttributes)).
                    Concat(Helpers.UserAttributesToDictionary(oAutoAttributes)).
                    ToDictionary(Function(kv) kv.Key, Function(kv) kv.Value)

                Logger.Info("Writing [{0}] Attributes for ObjectId [{0}] ", oResponse.ObjectId)
                WriteAttributeValues(oResponse.ObjectId, oFinalAttributes)

                'TODO: Write to TBGI_INDEX_HISTORY?

                ' Finally, commit the transaction
                Transaction?.Commit()

                Return New ImportFileResponse(oResponse.ObjectId)

            Catch ex As Exception
                Logger.Warn("Error occurred while importing file!")
                Logger.Error(ex)

                Logger.Info("Rolling back transaction.")
                Transaction?.Rollback()

                Return New ImportFileResponse(ex)
            End Try
        End Function

        Private Function GetVirtualPath(pFileInfo As FileInfo, pPathConvention As String, pUser As UserState, pUserAttributes As List(Of UserAttributeValue), pAutoAttributes As List(Of UserAttributeValue))
            Logger.Info("Generating virtual path for file [{0}]", pFileInfo.Name)

            Dim oUserAttributeDict = Helpers.UserAttributesToDictionary(pUserAttributes)
            Dim oAutoAttributeDict = Helpers.UserAttributesToDictionary(pAutoAttributes)

            If pPathConvention Is Nothing OrElse pPathConvention = String.Empty Then
                Logger.Warn("Virtual path template for File [{0}] was empty. Returning nothing.", pFileInfo.Name)
                Return Nothing

            End If

            Dim oDynamicPath As String = Helpers.GetPlaceholderValue(pPathConvention, pFileInfo, pUser, oUserAttributeDict, oAutoAttributeDict)
            Logger.Info("Virtual Path for file [{0}] is [{1}]", pFileInfo.Name, oDynamicPath)

            Return oDynamicPath
        End Function

        Private Function GetFilenameByNameconvention(pFileInfo As FileInfo, pNameconvention As String, pUser As UserState, pUserAttributes As List(Of UserAttributeValue), pAutoAttributes As List(Of UserAttributeValue)) As String
            Logger.Info("Generating display filename for file [{0}]", pFileInfo.Name)

            Dim oUserAttributeDict = Helpers.UserAttributesToDictionary(pUserAttributes)
            Dim oAutoAttributeDict = Helpers.UserAttributesToDictionary(pAutoAttributes)

            If pNameconvention Is Nothing OrElse pNameconvention = String.Empty Then
                Logger.Warn("Nameconvention for File [{0}] was empty. Returning original filename.", pFileInfo.Name)
                Return pFileInfo.Name

            End If

            Dim oFileName As String = Helpers.GetPlaceholderValue(pNameconvention, pFileInfo, pUser, oUserAttributeDict, oAutoAttributeDict)
            Logger.Info("Display Filename for file [{0}] is [{1}]", pFileInfo.Name, oFileName)

            Return oFileName & pFileInfo.Extension
        End Function

        Private Sub WriteAttributeValues(pObjectId As Long, pAttributes As Dictionary(Of String, List(Of String)))
            For Each oAttribute As KeyValuePair(Of String, List(Of String)) In pAttributes
                Try
                    ' TODO: This works only for simple attributes for now!!!
                    Dim oValue = oAttribute.Value.FirstOrDefault()

                    ' Dont write empty attributes
                    If oValue Is Nothing Then
                        Continue For
                    End If

                    ' Now make the call to the database
                    Dim oSuccess = Helpers.SetAttributeValue(Connection, Transaction, pObjectId, oAttribute.Key, oValue, User.Language, User.UserName)
                    If oSuccess Then
                        Logger.Info("Attribute written [{0}] => [{1}]", oAttribute.Key, oAttribute.Value.First())
                    Else
                        Logger.Warn("Attribute value could not be written")
                    End If
                Catch ex As Exception
                    LogAndThrow(ex, $"Attribute [{oAttribute.Key}] could not be written!")
                End Try
            Next
        End Sub
    End Class

End Namespace