Imports System.Data.SqlClient
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Database.MSSQLServer.TransactionMode
Imports DigitalData.Modules.Logging
Imports DigitalData.Services.EDMIService.Methods
Imports DigitalData.Services.EDMIService.GlobalState

Namespace Methods.IDB.UpdateFile
    Public Class UpdateFileMethod
        Inherits BaseMethod

        Private ReadOnly Connection As SqlConnection
        Private ReadOnly Transaction As SqlTransaction

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

            Connection = DatabaseIDB.GetConnection()
            Transaction = Connection.BeginTransaction()
        End Sub

        Public Function Run(pData As UpdateFileRequest) As UpdateFileResponse
            Try
                ' TODO: Update file object
                If Helpers.TestObjectIdExists(pData.ObjectId) = False Then
                    LogAndThrow("ObjectId does not exist!")
                End If

                'TODO: Create a view that collects all information about an idb object
                Dim oResultObjectId As Long

                Logger.Debug("Creating new Version: [{0}]", pData.CreateNewVersion)

                If pData.CreateNewVersion = False Then
                    ' ----------------------------------------------
                    ' -- Replace the existing file-object
                    ' ----------------------------------------------

                    Dim oGetFileObject As New GetFileObject.GetFileObjectMethod(LogConfig, DatabaseIDB, DatabaseECM, GlobalState)
                    Dim oArgs = New GetFileObject.GetFileObjectRequest With {
                        .ObjectId = pData.ObjectId,
                        .LoadFileContents = False
                    }
                    Dim oFileObjectResponse As GetFileObject.GetFileObjectResponse = oGetFileObject.Run(oArgs)

                    If oFileObjectResponse.OK = False Then
                        LogAndThrow(oFileObjectResponse.ErrorMessage)
                    End If

                    Dim oFileObjectSize As Long = pData.File.FileContents.Length
                    Dim oFileObject As GetFileObject.FileObject = oFileObjectResponse.FileObject
                    Dim oFilePath As String = oFileObject.FilePath

                    Try
                        Using oStream = New IO.FileStream(oFilePath, IO.FileMode.Create, IO.FileAccess.Write)
                            Logger.Info("Saving file to path [{0}]", oFilePath)
                            oStream.Write(pData.File.FileContents, 0, oFileObjectSize)
                            oStream.Flush(True)
                            oStream.Close()
                        End Using
                    Catch ex As Exception
                        LogAndThrow(ex, $"Could not write file [{oFilePath}] to disk!")
                    End Try

                    oResultObjectId = pData.ObjectId

                Else
                    ' ----------------------------------------------
                    ' -- Create a new object + file object
                    ' ----------------------------------------------

                    Dim oObjectTable = DatabaseIDB.GetDatatable($"Select * FROM VWIDB_OBJECT WHERE IDB_OBJ_ID = {pData.ObjectId}")
                    Dim oObjectRow As DataRow = oObjectTable.Rows.Item(0)
                    Dim oKind As String = oObjectRow.Item("KIND_NAME")
                    Dim oBusinessEntity As String = oObjectRow.Item("BE_NAME")
                    Dim oStore As String = oObjectRow.Item("STORE_NAME")

                    Logger.Debug("Getting information for ObjectId [{0}]", pData.ObjectId)
                    Logger.Debug("Kind: [{0}]", oKind)
                    Logger.Debug("BE: [{0}]", oBusinessEntity)
                    Logger.Debug("Store: [{0}]", oStore)

                    Dim oNewFileMethod As New NewFile.NewFileMethod(LogConfig, DatabaseIDB, DatabaseECM, GlobalState)
                    Dim oNewFileRequest As New NewFile.NewFileRequest With {
                        .File = pData.File,
                        .IDBDoctypeId = oBusinessEntity,
                        .KindType = oKind,
                        .StoreName = oStore,
                        .User = pData.User
                    }
                    Dim oNewFileResponse = oNewFileMethod.Run(oNewFileRequest)

                    If oNewFileResponse.OK = False Then
                        LogAndThrow(oNewFileResponse.ErrorMessage)
                    End If

                    Dim oNewObjectId As Long = oNewFileResponse.ObjectId
                    Logger.Debug("New file Version has ObjectId [{0}]", oNewObjectId)

                    Dim oSql As String = $"EXEC PRIDB_NEW_VERSION_OBJECT '{pData.ObjectId}', '{oNewObjectId}', '{pData.User.UserName}'"
                    DatabaseIDB.ExecuteNonQuery(oSql)
                    Logger.Debug("Versioning complete from [{0}] to [{1}]", pData.ObjectId, oNewObjectId)

                    oResultObjectId = oNewObjectId

                End If

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

                Return New UpdateFileResponse(oResultObjectId)
            Catch ex As Exception
                Logger.Warn("Error occurred while updating file!")
                Logger.Error(ex)

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

                Return New UpdateFileResponse(ex)
            End Try
        End Function

        Private Function TestFileChecksumExists(pChecksum As String) As Long
            Try
                Dim oChecksumSQL = $"SELECT IDB_OBJ_ID FROM TBIDB_FILE_OBJECT WHERE FILE_HASH = '{pChecksum}'"
                Dim oExistingObjectId As Long = DatabaseIDB.GetScalarValue(oChecksumSQL)

                If oExistingObjectId > 0 Then
                    Logger.Info("Returning early with ObjectId [{0}] because Checksum [{1}] already exists.", oExistingObjectId, pChecksum)
                    Return oExistingObjectId
                End If

                Return Nothing

            Catch ex As Exception
                Logger.Error(ex)
                Return Nothing

            End Try
        End Function

        Private Function NewObjectId(pKindType As String, pBusinessEntity As String, pWho As String) As Long
            Try
                Dim oNewObjectIdSQL = $"DECLARE @NEW_IDB_OBJ_ID BIGINT
                            EXEC PRIDB_NEW_OBJECT '{pKindType}','{pWho}','{pBusinessEntity}',0, @IDB_OBJ_ID = @NEW_IDB_OBJ_ID OUTPUT;
                            SELECT @NEW_IDB_OBJ_ID"
                Dim oObjectId As Long = DatabaseIDB.GetScalarValueWithConnectionObject(oNewObjectIdSQL, Connection, ExternalTransaction, Transaction)
                Logger.Info("New Object with Id [{0}] created!", oObjectId)

                If IsNothing(oObjectId) Then
                    LogAndThrow("Could not create new ObjectId!")
                End If

                Return oObjectId
            Catch ex As Exception
                Logger.Error(ex)
                Return Nothing
            End Try
        End Function

        Private Function GetFileObjectFileName(IDB_OBJ_ID As Long, pFilename As String, pKeepFilename As Boolean) As String
            ' TODO: save actual extensions
            If pKeepFilename Then
                Return pFilename
            Else
                Return $"{IDB_OBJ_ID}.ddfo"
            End If
        End Function

        Private Function GetDateSubDirectory(pDate As Date) As String
            Return IO.Path.Combine(pDate.ToString("yyyy"), pDate.ToString("MM"), pDate.ToString("dd"))
        End Function
    End Class

End Namespace