(function() {
    // Definisi directive
    var moneyFormat = {
      bind: function(el, binding, vnode) {
        var inputElement = el.tagName === 'INPUT' ? el : el.querySelector('input');
        if (!inputElement) return;
        
        var vm = vnode.context;
        var modelName = binding.expression;
        
        // Tambahkan state untuk input
        el._moneyFormat = {
          hasDecimal: false,       // Flag apakah ada koma desimal
          decimalPart: '',         // Bagian desimal (setelah koma)
          oldValue: '',            // Nilai input sebelumnya
          oldCursorPosition: 0     // Posisi kursor sebelumnya
        };
        
        // Format nilai awal
        if (vm[modelName]) {
          var formattedValue = formatNumber(vm[modelName]);
          inputElement.value = formattedValue;
          
          // Set flags
          el._moneyFormat.hasDecimal = formattedValue.includes(',');
          if (el._moneyFormat.hasDecimal) {
            var parts = formattedValue.split(',');
            el._moneyFormat.decimalPart = parts.length > 1 ? parts[1] : '';
          }
          el._moneyFormat.oldValue = formattedValue;
        }
        
        // Format angka untuk display
        function formatNumber(value) {
          if (!value && value !== 0) return '';
          
          // Konversi ke string
          var strValue = String(value);
          
          // Ganti titik dengan koma untuk desimal
          strValue = strValue.replace('.', ',');
          
          // Split berdasarkan koma
          var parts = strValue.split(',');
          var integerPart = parts[0];
          var decimalPart = parts.length > 1 ? parts[1] : '';
          
          // Format bagian integer dengan titik ribuan
          var formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
          
          // Gabungkan kembali
          return decimalPart ? formattedInteger + ',' + decimalPart : formattedInteger;
        }
        
        // Convert dari display format ke nilai untuk model
        function parseNumber(displayValue) {
          if (!displayValue) return '';
          
          // Split berdasarkan koma
          var parts = displayValue.split(',');
          var integerPart = parts[0].replace(/\./g, ''); // Hapus titik ribuan
          var decimalPart = parts.length > 1 ? parts[1] : '';
          
          // Gabungkan dengan format JavaScript
          return decimalPart ? integerPart + '.' + decimalPart : integerPart;
        }
        
        // Handler saat pengguna menekan tombol (keydown)
        function onKeydown(e) {
          // Khusus untuk koma dan titik (input desimal)
          if (e.key === ',' || e.key === '.') {
            e.preventDefault(); // Cegah default behavior
            
            // Jika sudah ada koma, jangan tambahkan lagi
            if (el._moneyFormat.hasDecimal) return;
            
            // Posisi kursor saat ini
            var cursorPos = inputElement.selectionStart;
            
            // Tambahkan koma pada posisi kursor
            var currentValue = inputElement.value;
            var newValue = currentValue.substring(0, cursorPos) + ',' + currentValue.substring(cursorPos);
            
            // Update nilai input
            inputElement.value = newValue;
            
            // Simpan flag
            el._moneyFormat.hasDecimal = true;
            el._moneyFormat.decimalPart = '';
            
            // Update model
            var modelValue = parseNumber(newValue);
            vm.$set(vm, modelName, modelValue);
            
            // Simpan state baru
            el._moneyFormat.oldValue = newValue;
            el._moneyFormat.oldCursorPosition = cursorPos + 1;
            
            // Posisikan kursor setelah koma
            setTimeout(function() {
              inputElement.setSelectionRange(cursorPos + 1, cursorPos + 1);
            }, 0);
          }
          
          // Simpan posisi kursor saat ini untuk referensi input handler
          el._moneyFormat.oldCursorPosition = inputElement.selectionStart;
          el._moneyFormat.oldValue = inputElement.value;
        }
        
        // Handler saat nilai input berubah
        function onInput(e) {
          // Nilai saat ini
          var currentValue = inputElement.value;
          var cursorPos = inputElement.selectionStart;
          
          // Abaikan jika nilai tidak berubah
          if (currentValue === el._moneyFormat.oldValue) return;
          
          // Logika utama: Jika sudah ada koma sebelumnya
          if (el._moneyFormat.hasDecimal) {
            // Periksa apakah koma masih ada
            if (currentValue.includes(',')) {
              // Koma masih ada, format bagian integer dan pertahankan desimal
              var parts = currentValue.split(',');
              var integerPart = parts[0];
              var newDecimalPart = parts.length > 1 ? parts[1] : '';
              
              // Format bagian integer
              var cleanInteger = integerPart.replace(/\./g, '');
              var formattedInteger = cleanInteger.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
              
              // Gabungkan dengan desimal
              var formattedValue = formattedInteger + ',' + newDecimalPart;
              
              // Update model
              var modelValue = cleanInteger + (newDecimalPart ? '.' + newDecimalPart : '');
              vm.$set(vm, modelName, modelValue);
              
              // Update nilai input
              inputElement.value = formattedValue;
              
              // Update state
              el._moneyFormat.hasDecimal = true;
              el._moneyFormat.decimalPart = newDecimalPart;
              el._moneyFormat.oldValue = formattedValue;
              
              // Perbarui posisi kursor
              var newCursorPos;
              if (cursorPos <= parts[0].length) {
                // Kursor di bagian integer
                var oldDots = (integerPart.substring(0, cursorPos).match(/\./g) || []).length;
                var newDots = (formattedInteger.substring(0, cursorPos).match(/\./g) || []).length;
                newCursorPos = cursorPos + (newDots - oldDots);
              } else {
                // Kursor di bagian desimal
                var offsetFromComma = cursorPos - parts[0].length - 1;
                newCursorPos = formattedInteger.length + 1 + offsetFromComma;
              }
              
              setTimeout(function() {
                inputElement.setSelectionRange(newCursorPos, newCursorPos);
                el._moneyFormat.oldCursorPosition = newCursorPos;
              }, 0);
            } else {
              // Koma hilang, tambahkan kembali
              var oldValue = el._moneyFormat.oldValue;
              var oldCommaPos = oldValue.indexOf(',');
              
              // Bagian sebelum dan setelah koma di nilai lama
              var oldBeforeComma = oldValue.substring(0, oldCommaPos);
              var oldAfterComma = oldValue.substring(oldCommaPos + 1);
              
              // Kasus khusus: jika user menghapus semua
              if (currentValue === '') {
                el._moneyFormat.hasDecimal = false;
                el._moneyFormat.decimalPart = '';
                el._moneyFormat.oldValue = '';
                vm.$set(vm, modelName, '');
                return;
              }
              
              // Logika: koma dihapus, coba pulihkan
              
              // Kasus 1: Menghapus karakter tepat sebelum koma
              if (cursorPos === oldCommaPos) {
                // Format bagian integer
                var cleanCurrentValue = currentValue.replace(/\./g, '');
                var formattedInteger = cleanCurrentValue.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
                
                // Gabungkan dengan bagian desimal
                var restoredValue = formattedInteger + ',' + el._moneyFormat.decimalPart;
                
                // Update input
                inputElement.value = restoredValue;
                
                // Update model
                var modelValue = cleanCurrentValue + '.' + el._moneyFormat.decimalPart;
                vm.$set(vm, modelName, modelValue);
                
                // Perbarui state
                el._moneyFormat.oldValue = restoredValue;
                
                // Set kursor
                setTimeout(function() {
                  var newCommaPos = formattedInteger.length;
                  inputElement.setSelectionRange(newCommaPos, newCommaPos);
                  el._moneyFormat.oldCursorPosition = newCommaPos;
                }, 0);
                
                return;
              }
              
              // Kasus 2: Menghapus koma itu sendiri
              if (cursorPos === oldCommaPos || cursorPos === oldCommaPos + 1) {
                // Format bagian integer
                var cleanCurrentValue = currentValue.replace(/\./g, '');
                var formattedInteger = cleanCurrentValue.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
                
                // Gabungkan dengan bagian desimal yang disimpan
                var restoredValue = formattedInteger + ',' + el._moneyFormat.decimalPart;
                
                // Update input
                inputElement.value = restoredValue;
                
                // Update model
                var modelValue = cleanCurrentValue + '.' + el._moneyFormat.decimalPart;
                vm.$set(vm, modelName, modelValue);
                
                // Perbarui state
                el._moneyFormat.oldValue = restoredValue;
                
                // Set kursor
                setTimeout(function() {
                  var newCommaPos = formattedInteger.length;
                  var newCursorPos = newCommaPos + 1; // Setelah koma
                  inputElement.setSelectionRange(newCursorPos, newCursorPos);
                  el._moneyFormat.oldCursorPosition = newCursorPos;
                }, 0);
                
                return;
              }
              
              // Format bagian integer dan tambahkan koma
              var cleanValue = currentValue.replace(/\./g, '');
              var formattedInteger = cleanValue.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
              var restoredValue = formattedInteger + ',' + el._moneyFormat.decimalPart;
              
              // Update input
              inputElement.value = restoredValue;
              
              // Update model
              var modelValue = cleanValue + '.' + el._moneyFormat.decimalPart;
              vm.$set(vm, modelName, modelValue);
              
              // Perbarui state
              el._moneyFormat.oldValue = restoredValue;
              
              // Perhitungan kursor
              setTimeout(function() {
                var newCursorPos;
                
                if (cursorPos < oldCommaPos) {
                  // Kursor di bagian integer
                  var oldDots = (oldValue.substring(0, cursorPos).match(/\./g) || []).length;
                  var newDots = (formattedInteger.substring(0, cursorPos).match(/\./g) || []).length;
                  newCursorPos = cursorPos + (newDots - oldDots);
                } else {
                  // Kursor di bagian desimal, kembalikan ke setelah koma
                  newCursorPos = formattedInteger.length + 1;
                }
                
                inputElement.setSelectionRange(newCursorPos, newCursorPos);
                el._moneyFormat.oldCursorPosition = newCursorPos;
              }, 0);
            }
          } else {
            // Belum ada koma, format bagian integer saja
            
            // Kasus khusus: jika user menambahkan koma
            if (currentValue.includes(',')) {
              // Ada koma baru, update flags
              var parts = currentValue.split(',');
              var integerPart = parts[0];
              var decimalPart = parts.length > 1 ? parts[1] : '';
              
              // Format bagian integer
              var cleanInteger = integerPart.replace(/\./g, '');
              var formattedInteger = cleanInteger.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
              
              // Gabungkan
              var formattedValue = formattedInteger + ',' + decimalPart;
              
              // Update input
              inputElement.value = formattedValue;
              
              // Update model
              var modelValue = cleanInteger + (decimalPart ? '.' + decimalPart : '.');
              vm.$set(vm, modelName, modelValue);
              
              // Perbarui state
              el._moneyFormat.hasDecimal = true;
              el._moneyFormat.decimalPart = decimalPart;
              el._moneyFormat.oldValue = formattedValue;
              
              // Set kursor
              var commaPos = formattedInteger.length;
              var newCursorPos;
              
              if (cursorPos <= parts[0].length) {
                // Kursor di bagian integer
                var oldDots = (integerPart.substring(0, cursorPos).match(/\./g) || []).length;
                var newDots = (formattedInteger.substring(0, cursorPos).match(/\./g) || []).length;
                newCursorPos = cursorPos + (newDots - oldDots);
              } else {
                // Kursor di bagian desimal
                var offsetFromComma = cursorPos - parts[0].length - 1;
                newCursorPos = commaPos + 1 + offsetFromComma;
              }
              
              setTimeout(function() {
                inputElement.setSelectionRange(newCursorPos, newCursorPos);
                el._moneyFormat.oldCursorPosition = newCursorPos;
              }, 0);
              
              return;
            }
            
            // Format bagian integer (tanpa desimal)
            var cleanValue = currentValue.replace(/\./g, '');
            var formattedValue = cleanValue.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
            
            // Update hanya jika berbeda
            if (formattedValue !== currentValue) {
              // Hitung offset kursor
              var oldDots = (currentValue.substring(0, cursorPos).match(/\./g) || []).length;
              var newDots = (formattedValue.substring(0, cursorPos).match(/\./g) || []).length;
              var offset = newDots - oldDots;
              
              // Update input
              inputElement.value = formattedValue;
              
              // Update model
              vm.$set(vm, modelName, cleanValue);
              
              // Perbarui state
              el._moneyFormat.oldValue = formattedValue;
              
              // Update kursor
              var newCursorPos = cursorPos + offset;
              setTimeout(function() {
                inputElement.setSelectionRange(newCursorPos, newCursorPos);
                el._moneyFormat.oldCursorPosition = newCursorPos;
              }, 0);
            } else {
              // Tidak perlu format ulang
              vm.$set(vm, modelName, cleanValue);
              el._moneyFormat.oldValue = formattedValue;
              el._moneyFormat.oldCursorPosition = cursorPos;
            }
          }
        }
        
        // Format ulang saat keluar dari input
        function onBlur() {
          var modelValue = vm[modelName];
          if (modelValue !== undefined && modelValue !== null) {
            var formattedValue = formatNumber(modelValue);
            inputElement.value = formattedValue;
            
            // Update flags
            el._moneyFormat.hasDecimal = formattedValue.includes(',');
            if (el._moneyFormat.hasDecimal) {
              var parts = formattedValue.split(',');
              el._moneyFormat.decimalPart = parts.length > 1 ? parts[1] : '';
            } else {
              el._moneyFormat.decimalPart = '';
            }
            
            el._moneyFormat.oldValue = formattedValue;
          }
        }
        
        // Register event handlers
        inputElement.addEventListener('keydown', onKeydown);
        inputElement.addEventListener('input', onInput);
        inputElement.addEventListener('blur', onBlur);
        
        // Store untuk cleanup
        el._moneyFormat.handlers = {
          keydown: onKeydown,
          input: onInput,
          blur: onBlur
        };
      },
      
      update: function(el, binding, vnode) {
        var inputElement = el.tagName === 'INPUT' ? el : el.querySelector('input');
        if (!inputElement || !el._moneyFormat) return;
        
        var vm = vnode.context;
        var modelName = binding.expression;
        
        // Format untuk display
        function formatNumber(value) {
          if (!value && value !== 0) return '';
          
          // Konversi ke string
          var strValue = String(value);
          
          // Ganti titik dengan koma untuk desimal
          strValue = strValue.replace('.', ',');
          
          // Split berdasarkan koma
          var parts = strValue.split(',');
          var integerPart = parts[0];
          var decimalPart = parts.length > 1 ? parts[1] : '';
          
          // Format bagian integer dengan titik ribuan
          var formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
          
          // Gabungkan kembali
          return decimalPart ? formattedInteger + ',' + decimalPart : formattedInteger;
        }
        
        // Update display jika tidak sedang fokus
        if (document.activeElement !== inputElement) {
          var modelValue = vm[modelName];
          if (modelValue !== undefined && modelValue !== null) {
            var formattedValue = formatNumber(modelValue);
            inputElement.value = formattedValue;
            
            // Update flags
            el._moneyFormat.hasDecimal = formattedValue.includes(',');
            if (el._moneyFormat.hasDecimal) {
              var parts = formattedValue.split(',');
              el._moneyFormat.decimalPart = parts.length > 1 ? parts[1] : '';
            } else {
              el._moneyFormat.decimalPart = '';
            }
            
            el._moneyFormat.oldValue = formattedValue;
          }
        }
      },
      
      unbind: function(el) {
        var inputElement = el.tagName === 'INPUT' ? el : el.querySelector('input');
        if (!inputElement || !el._moneyFormat || !el._moneyFormat.handlers) return;
        
        // Remove event listeners
        inputElement.removeEventListener('keydown', el._moneyFormat.handlers.keydown);
        inputElement.removeEventListener('input', el._moneyFormat.handlers.input);
        inputElement.removeEventListener('blur', el._moneyFormat.handlers.blur);
        
        // Cleanup
        delete el._moneyFormat;
      }
    };
  
    // Register directive globally jika Vue tersedia
    if (typeof Vue !== 'undefined') {
      Vue.directive('money-format', moneyFormat);
    }
    
    // Export untuk CommonJS/AMD
    if (typeof exports === 'object' && typeof module !== 'undefined') {
      module.exports = moneyFormat;
    } else if (typeof define === 'function' && define.amd) {
      define(function() { return moneyFormat; });
    } else {
      // Browser global
      window.moneyFormat = moneyFormat;
    }
  })();