Public Class ClassIDBData
    Public DTVWIDB_BE_ATTRIBUTE As DataTable
    Public IDBSystemIndices As List(Of String)
    ''' <summary>
    ''' Wenn True, werden SQL-Statements nicht sofort ausgeführt,
    ''' sondern in <see cref="_sqlBatch"/> gesammelt.
    ''' </summary>
    Public Property BatchMode As Boolean = False
    Private _sqlBatch As New List(Of String)

    ''' <summary>
    ''' Startet den Batch-Sammelmodus.
    ''' </summary>
    Public Sub BeginBatch()
        _sqlBatch.Clear()
        BatchMode = True
    End Sub
    ''' <summary>
    ''' Führt alle gesammelten SQL-Statements als einen einzigen String
    ''' an ExecuteNonQueryIDB weiter. Jeder Block wird in BEGIN...END
    ''' gekapselt, damit DECLARE-Variablen nicht kollidieren.
    ''' </summary>
    ''' <returns>True wenn erfolgreich</returns>
    Public Function CommitBatch() As Boolean
        BatchMode = False
        If _sqlBatch.Count = 0 Then Return True
        Try
            Dim oStatements = _sqlBatch.
                Where(Function(s) Not String.IsNullOrWhiteSpace(s)).
                ToList()

            ' @NEW_OBJ_MD_ID pro Statement eindeutig umbenennen → kein Namenskonflikt im Batch
            Dim oNumberedStatements As New List(Of String)
            Dim oIndex As Integer = 0
            For Each oStatement As String In oStatements
                Dim oNumbered = oStatement.Replace("@NEW_OBJ_MD_ID", $"@NEW_OBJ_MD_ID_{oIndex}")
                oNumberedStatements.Add(oNumbered)
                oIndex += 1
            Next

            Dim oBatchSQL = String.Join(vbNewLine, oNumberedStatements)
            LOGGER.Debug($"⚡ CommitBatch - Executing {oStatements.Count} statements as one batch:{vbNewLine}{oBatchSQL}")
            Dim oResult = DatabaseFallback.ExecuteNonQueryIDB(oBatchSQL)
            _sqlBatch.Clear()
            Return oResult
        Catch ex As Exception
            LOGGER.Error(ex)
            _sqlBatch.Clear()
            Return False
        End Try
    End Function

    ''' <summary>
    ''' Verwirft alle gesammelten Statements ohne Ausführung.
    ''' </summary>
    Public Sub RollbackBatch()
        _sqlBatch.Clear()
        BatchMode = False
    End Sub

    ''' <summary>
    ''' Führt ein SQL-Statement aus – sofort oder gesammelt je nach BatchMode.
    ''' </summary>
    Private Function ExecuteOrQueue(oSQL As String) As Boolean
        If BatchMode Then
            _sqlBatch.Add(oSQL)
            LOGGER.Debug($"BatchMode - Queued statement: {oSQL}")
            Return True
        Else
            Return DatabaseFallback.ExecuteNonQueryIDB(oSQL)
        End If
    End Function
    ''' <summary>
    ''' Gets all indices by BusinessEntity.
    ''' </summary>
    ''' <param name="BusinessEntity">Title of Business Entity</param>
    ''' <returns>Array with all Indices</returns>
    ''' <remarks></remarks>
    ''' 
    Public Function Init() As Boolean
        Dim oSQL = $"SELECT DISTINCT ATTR_TITLE, TYP_ID, TYP_ID as [TYPE_ID] FROM VWIDB_BE_ATTRIBUTE WHERE SYS_ATTRIBUTE = 0 ORDER BY ATTR_TITLE"
        DTVWIDB_BE_ATTRIBUTE = DatabaseFallback.GetDatatableIDB(oSQL)
        If IsNothing(DTVWIDB_BE_ATTRIBUTE) Then
            oSQL = $"SELECT DISTINCT ATTR_TITLE, TYP_ID, TYP_ID as [TYPE_ID] FROM VWIDB_BE_ATTRIBUTE ORDER BY ATTR_TITLE "
            DTVWIDB_BE_ATTRIBUTE = DatabaseFallback.GetDatatableIDB(oSQL)
        End If
        Return True
    End Function

    Public Function GetIndicesByBE(ByVal BusinessEntity As String) As String()
        Try
            Dim aNames(4) As String
            aNames(0) = "ObjectID"
            aNames(1) = "IDBCreatedWhen"
            aNames(2) = "IDBCreatedWho"
            aNames(3) = "IDBChangedWhen"
            aNames(4) = "IDBChangedWho"
            IDBSystemIndices = aNames.ToList
            ' Array für Indizes vorbereiten
            Dim aIndexNames(DTVWIDB_BE_ATTRIBUTE.Rows.Count + 4) As String
            Dim oCount As Integer = 0
            aIndexNames(oCount) = "ObjectID"
            oCount += 1
            aIndexNames(oCount) = "IDBCreatedWhen"
            oCount += 1
            aIndexNames(oCount) = "IDBCreatedWho"
            oCount += 1
            aIndexNames(oCount) = "IDBChangedWhen"
            oCount += 1
            aIndexNames(oCount) = "IDBChangedWho"
            For Each oRow As DataRow In DTVWIDB_BE_ATTRIBUTE.Rows
                oCount += 1
                aIndexNames(oCount) = oRow.Item("ATTR_TITLE")

            Next


            ' Indexarray sortiert zurückgeben
            Array.Sort(aIndexNames)
            ' Indexarray zurückgeben
            Return aIndexNames

        Catch ex As Exception
            LOGGER.Error(ex)
            MsgBox(ex.Message, MsgBoxStyle.Critical, "Error getting the IDB Indicies")
            Return Nothing
        End Try
    End Function
    Public Function GetTypeOfIndex(ByVal indexname As String) As Integer
        Try
            For Each oRow As DataRow In DTVWIDB_BE_ATTRIBUTE.Rows
                If oRow.Item("ATTR_TITLE") = indexname Then
                    Try
                        Dim oType = oRow.Item("TYP_ID")
                        Return oType
                    Catch ex As Exception
                        Try
                            Dim oType = oRow.Item("TYP_ID")
                            Return oType
                        Catch ex1 As Exception
                            LOGGER.Error(ex)
                            Return Nothing
                        End Try

                    End Try

                End If
            Next

        Catch ex As Exception
            LOGGER.Error(ex)
            Return Nothing
        End Try

    End Function
    Public Function GetVariableValue(oAttributeName As String, Optional oIDBTyp As Integer = 0, Optional FromIDB As Boolean = False) As Object
        Try
            ' Bestimme, ob es sich um ein Single-Value-Attribut handelt (nicht Typ 8 oder 9)
            Dim oIsSingleAttribute As Boolean = (oIDBTyp <> 8 AndAlso oIDBTyp <> 9)

            LOGGER.Debug($"IDBData - GetVariableValue - Attribute: [{oAttributeName}] - IsSingleAttribute: [{oIsSingleAttribute}] - FromIDB: [{FromIDB}]")

            ' Schnellpfad: Direkt aus gecachter DataTable holen
            If oIsSingleAttribute AndAlso IDB_DT_DOC_DATA.Rows.Count = 1 AndAlso Not FromIDB Then
                Try
                    Dim oMappedName As String = MapSystemAttributeName(oAttributeName)
                    Dim oValue As Object = IDB_DT_DOC_DATA.Rows(0).Item(oMappedName)
                    LOGGER.Debug($"IDBData - GetVariableValue - Retrieved from cache: Attribute=[{oAttributeName}] MappedName=[{oMappedName}] Value=[{oValue}]")
                    Return oValue
                Catch ex As Exception
                    LOGGER.Debug($"Error getting Attribute from IDB_DT_DOC_DATA: {ex.Message}")
                    ' Fallthrough zum Datenbank-Fallback
                End Try
            End If

            ' Fallback: Wert aus Datenbank über Funktion holen
            LOGGER.Debug($"Retrieving value for attribute [{oAttributeName}] via FNIDB_PM_GET_VARIABLE_VALUE")

            Dim oSQL As String = $"SELECT * FROM [dbo].[FNIDB_PM_GET_VARIABLE_VALUE] ({CURRENT_DOC_ID},'{oAttributeName}','{USER_LANGUAGE}',CONVERT(BIT,'{IDB_USES_WMFILESTORE}'))"
            LOGGER.Debug($"SQL: {oSQL}")

            Dim oResultTable As DataTable = DatabaseFallback.GetDatatableIDB(oSQL)

            If oResultTable IsNot Nothing AndAlso oResultTable.Rows.Count = 1 Then
                Dim oValue As Object = oResultTable.Rows(0).Item(0)
                LOGGER.Debug($"IDBData - GetVariableValue - Retrieved from DB: [{oValue}]")
                Return oValue
            Else
                LOGGER.Info($"IDBData - GetVariableValue - No value found in DB for attribute [{oAttributeName}] - SQL [{oSQL}]")
            End If

            Return oResultTable

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

    ''' <summary>
    ''' Mappt System-Attributnamen auf interne Spaltennamen.
    ''' </summary>
    Private Function MapSystemAttributeName(attributeName As String) As String
        Select Case attributeName
            Case "IDBCreatedWhen"
                Return "ADDED_WHEN"
            Case "IDBCreatedWho"
                Return "ADDED_WHO"
            Case "IDBChangedWhen"
                Return "CHANGED_WHEN"
            Case "IDBChangedWho"
                Return "CHANGED_WHO"
            Case Else
                Return attributeName
        End Select
    End Function
    Public Function Delete_Term_Object_From_Metadata(oAttributeName As String, oTerm2Delete As String) As Object
        Try
            Dim oID_IS_FOREIGN As Integer
            oID_IS_FOREIGN = 0
            If IDB_USES_WMFILESTORE Then
                oID_IS_FOREIGN = 1
            End If
            oTerm2Delete = oTerm2Delete.Replace("'", "''")
            Dim oDELSQL = $"EXEC PRIDB_DELETE_TERM_OBJECT_METADATA {CURRENT_DOC_ID},'{oAttributeName}','{oTerm2Delete}','{USER_USERNAME}','{USER_LANGUAGE}',{oID_IS_FOREIGN};"
            LOGGER.Debug($"Delete_Term_Object_From_Metadata: {oDELSQL}")
            'DatabaseFallback.ExecuteNonQueryIDB(oDELSQL)
            Return ExecuteOrQueue(oDELSQL)
        Catch ex As Exception
            LOGGER.Error(ex)
            Return Nothing
        End Try

    End Function
    Public Function Delete_AttributeData(pIDB_OBJID As Int64, pAttributeName As String) As Object
        Try
            Dim oDELSQL = $"EXEC PRIDB_DELETE_ATTRIBUTE_DATA {pIDB_OBJID},'{pAttributeName}','{USER_USERNAME}';"
            LOGGER.Debug($"Delete_Attribute_Data: {oDELSQL}")
            ' DatabaseFallback.ExecuteNonQueryIDB(oDELSQL)
            Return ExecuteOrQueue(oDELSQL)
        Catch ex As Exception
            LOGGER.Error(ex)
            Return Nothing
        End Try

    End Function

    Public Function SetVariableValue(oAttributeName As String, oNewValue As Object, Optional CheckDeleted As Boolean = False, Optional oIDBTyp As Integer = 0)
        Try
            Dim omsg = $"IDBData - SetVariableValue - Attribute: [{oAttributeName}] - NewValue: [{oNewValue}] - CheckDeleted: [{CheckDeleted.ToString}] - oIDBTyp: [{oIDBTyp}]"
            LOGGER.Debug(omsg)
            Dim omytype = oNewValue.GetType.ToString
            If omytype = "System.Data.DataTable" Then
                Dim oDTMyNewValues As DataTable = oNewValue
                Dim oAttributeResultFromDB
                Dim oTypeOldResult
                ' Für DataTable (Mehrfachauswahl/Vektor) IMMER auf gelöschte Werte prüfen,
                ' unabhängig vom übergebenen CheckDeleted-Parameter.
                Dim oEffectiveCheckDeleted As Boolean = True

                If oEffectiveCheckDeleted = True Then
                    oAttributeResultFromDB = GetVariableValue(oAttributeName, oIDBTyp)
                    oTypeOldResult = oAttributeResultFromDB.GetType.ToString
                    If TypeOf oAttributeResultFromDB Is DataTable Then
                        Dim myOldValues As DataTable = oAttributeResultFromDB
                        If myOldValues.Rows.Count >= 1 Then

                            'now Checking whether the old row still remains in Vector? If not it will be deleted as it cannot be replaced in multivalues
                            For Each oOldValueRow As DataRow In myOldValues.Rows
                                Dim oExists As Boolean = False
                                For Each oNewValueRow As DataRow In oDTMyNewValues.Rows
                                    Dim oInfo1 = $"Checking oldValue[{oOldValueRow.Item(0)}] vs NewValue [{oNewValueRow.Item(1)}]"
                                    If oNewValueRow.Item(1).ToString.ToUpper = oOldValueRow.Item(0).ToString.ToUpper Then
                                        oExists = True
                                        Exit For
                                    End If
                                Next

                                If oExists = False Then
                                    Dim oInfo = $"Value [{oOldValueRow.Item(0)}] no longer existing in Vector-Attribute [{oAttributeName}] - will be deleted!"
                                    LOGGER.Debug(oInfo)
                                    'SetVariableValue(CURRENT_PROFILE_LOG_INDEX, oInfo)
                                    Delete_Term_Object_From_Metadata(oAttributeName, oOldValueRow.Item(0))
                                End If

                            Next
                        End If
                    Else
                        '### Old Value is a single value ###
                        If oDTMyNewValues.Rows.Count > 1 Then
                            '### there is more than one new value ###
                            Dim oExists As Boolean = False
                            For Each oNewValueRow As DataRow In oDTMyNewValues.Rows
                                LOGGER.Debug($"Checking oldValue[{oAttributeResultFromDB}] vs NewValue [{oNewValueRow.Item(1)}]")
                                If oNewValueRow.Item(1).ToString.ToUpper = oAttributeResultFromDB.ToString.ToUpper Then
                                    oExists = True
                                    Exit For  ' ← sobald gefunden, abbrechen
                                End If
                            Next
                            If oExists = False Then
                                LOGGER.Debug($"Value [{oAttributeResultFromDB}] no longer existing in Attribute [{oAttributeName}] - will be deleted!")
                                'SetVariableValue(CURRENT_PROFILE_LOG_INDEX, oInfo2)
                                Delete_Term_Object_From_Metadata(oAttributeName, oAttributeResultFromDB)
                            End If
                        Else
                            '### there is only ONE new value ###
                            If oDTMyNewValues.Rows(0).Item(1) <> oAttributeResultFromDB Then
                                Dim oInfo = $"Value [{oAttributeResultFromDB}] of Attribute [{oAttributeName}] obviously was updated during runtime - will be deleted!"
                                LOGGER.Debug(oInfo)
                                SetVariableValue(CURRENT_PROFILE_LOG_INDEX, oInfo)
                                Delete_Term_Object_From_Metadata(oAttributeName, oAttributeResultFromDB)
                            Else
                                LOGGER.Debug($"Attributvalue of [{oAttributeName}] did not change!")
                            End If

                        End If

                    End If

                End If

                For Each oNewValueRow As DataRow In oDTMyNewValues.Rows
                    'Dim oSuccess As Boolean = False
                    Dim oVALUE = oNewValueRow.Item(1).ToString
                    oVALUE = oVALUE.Replace("'", "''")
                    Dim oPRSQL = $"DECLARE @NEW_OBJ_MD_ID BIGINT " & vbNewLine & $"EXEC PRIDB_NEW_OBJ_DATA {CURRENT_DOC_ID},'{oAttributeName}','{USER_USERNAME}','{oVALUE}','{USER_LANGUAGE}',0,@OMD_ID = @NEW_OBJ_MD_ID OUTPUT;"
                    LOGGER.Debug(oPRSQL)
                    'oSuccess = DatabaseFallback.ExecuteNonQueryIDB(oPRSQL)
                    If Not ExecuteOrQueue(oPRSQL) Then Return False
                    'If oSuccess = False Then
                    '    Return False
                    'End If
                Next
                Return True
            Else
                'oNewValue = oNewValue.Replace("'", "' + NCHAR(39) + '")
                oNewValue = oNewValue.Replace("'", "''")
                Dim oPRIDB_NEW_OBJ_DATA = $"DECLARE @NEW_OBJ_MD_ID BIGINT " & vbNewLine & $"EXEC PRIDB_NEW_OBJ_DATA {CURRENT_DOC_ID},'{oAttributeName}','{USER_USERNAME}','{oNewValue}','{USER_LANGUAGE}',0,@OMD_ID = @NEW_OBJ_MD_ID OUTPUT;"
                LOGGER.Debug(oPRIDB_NEW_OBJ_DATA)
                ' Return DatabaseFallback.ExecuteNonQueryIDB(oPRIDB_NEW_OBJ_DATA)
                Return ExecuteOrQueue(oPRIDB_NEW_OBJ_DATA)
            End If

        Catch ex As Exception
            LOGGER.Error(ex)
            Return False
        End Try
    End Function
End Class
