<template>
  <el-input v-bind="$attrs" v-model="internalValue" @input="handleInput" @blur="handleBlur" :placeholder="placeholder"
    :disabled="disabled" type="text">

    <template slot="prepend" v-if="prepend">
      {{ prepend }}
    </template>
  </el-input>
</template>

<script>
export default {
  name: 'DecimalInput',
  props: {
    value: {
      type: [Number, String],
      default: ''
    },
    decimalDigits: {
      type: Number,
      default: 6
    },
    placeholder: {
      type: String,
      default: '请输入'
    },
    disabled: {
      type: Boolean,
      default: false
    },
    prepend: {
      type: String,
      default: ''
    },
  },
  data() {
    return {
      internalValue: this.value !== null && this.value !== undefined ? String(this.value) : '',
      oldValue: null,
      oldPattern: null,
      patternRules: [
        { name: 'NA', pattern: /^NA$/i, inputPattern: /^N?A?$/i },
        { name: 'FRACTION', pattern: /^\d+(\/\d+)*$/, inputPattern: /^(\d+\/?)*$/ }
      ]
    };
  },
  watch: {
    value: {
      handler(newVal) {
        if (newVal === '' || newVal == null) {
          this.internalValue = '';
          this.oldValue = null;
          this.oldPattern = null;
        } else {
          const strVal = String(newVal);
          this.internalValue = strVal;
          this.updateOldValue(strVal);
        }
      },
      immediate: true
    }
  },
  methods: {
    updateOldValue(val) {
      for (const rule of this.patternRules) {
        if (rule.pattern.test(val)) {
          this.oldValue = val;
          this.oldPattern = rule;
          return true;
        }
      }
      return false;
    },

    getMatchingRule(val) {
      for (const rule of this.patternRules) {
        if (rule.inputPattern.test(val)) {
          return rule;
        }
      }
      return null;
    },

    handleInput(val) {
      if (val === '') {
        this.internalValue = '';
        this.$emit('input', '');
        return;
      }

      const upperVal = val.toUpperCase();
      let cleaned = val;
      let matchedRule = null;
      if (this.oldPattern) {
        // 检查是否是旧模式的延续（以oldValue开头）
        if (val.startsWith(this.oldValue)) {
          // 是旧模式的延续，检查是否符合inputPattern
          if (this.oldPattern.inputPattern.test(val)) {
            matchedRule = this.oldPattern;
            cleaned = val;
          } else {
            // 不符合，但如果是FRACTION类型，尝试特殊处理
            if (this.oldPattern.name === 'FRACTION') {
              cleaned = val.replace(/[^\d/]/g, '');
              const parts = cleaned.split('/');
              const validParts = [];
              for (let i = 0; i < parts.length; i++) {
                if (parts[i] !== '') {
                  validParts.push(parts[i]);
                }
              }
              cleaned = validParts.join('/');
              matchedRule = this.oldPattern;
            } else {
              cleaned = this.oldValue || '';
              this.internalValue = cleaned;
              return;
            }
          }
        } else if (this.oldPattern.inputPattern.test(val)) {
          // 不是延续，但符合inputPattern（可能是清空后重新输入）
          matchedRule = this.oldPattern;
          cleaned = val;
        } else {
          // 尝试匹配新规则
          matchedRule = this.getMatchingRule(val);
          if (!matchedRule) {
            cleaned = this.oldValue || '';
            this.internalValue = cleaned;
            return;
          }
        }
      } else {
        matchedRule = this.getMatchingRule(val);
        
        if (matchedRule) {
          if (matchedRule.name === 'FRACTION') {
            cleaned = val.replace(/[^\d/]/g, '');
            const parts = cleaned.split('/');
            const validParts = [];
            for (let i = 0; i < parts.length; i++) {
              if (parts[i] !== '') {
                validParts.push(parts[i]);
              }
            }
            cleaned = validParts.join('/');
          } else {
            cleaned = upperVal;
          }
        } else {
          cleaned = val
            .replace(/[^\d.-]/g, '')
            .replace(/^(-)\1+/, '$1');

          const firstDotIndex = cleaned.indexOf('.');
          if (firstDotIndex !== -1) {
            const before = cleaned.slice(0, firstDotIndex);
            const after = cleaned.slice(firstDotIndex + 1).replace(/\./g, '');
            cleaned = before + '.' + after;
          }

          if (this.decimalDigits > 0 && cleaned.includes('.')) {
            const [intPart, decPart = ''] = cleaned.split('.');
            cleaned = intPart + '.' + decPart.slice(0, this.decimalDigits);
          } else if (this.decimalDigits === 0) {
            cleaned = cleaned.split('.')[0];
          }

          if (cleaned === '.') cleaned = '0.';
          else if (cleaned === '-.') cleaned = '-0.';
          else if (cleaned.startsWith('.')) cleaned = '0' + cleaned;
          else if (cleaned.startsWith('-.')) cleaned = '-0.' + cleaned.slice(2);

          if (cleaned.includes('.')) {
            const [int, dec] = cleaned.split('.');
            let newInt = int;
            if (/^-?0+\d/.test(int)) {
              newInt = int.replace(/^-?0+(\d)/, '$1');
            } else if (int === '' || int === '-') {
              newInt = int + '0';
            } else if (int === '00' || /^-00+$/.test(int)) {
              newInt = int.startsWith('-') ? '-0' : '0';
            }
            cleaned = newInt + '.' + dec;
          } else {
            if (/^-?0+\d/.test(cleaned)) {
              cleaned = cleaned.replace(/^-?0+(\d)/, '$1');
            } else if (cleaned === '00' || /^-00+$/.test(cleaned)) {
              cleaned = cleaned.startsWith('-') ? '-0' : '0';
            }
          }
        }
      }

      this.internalValue = cleaned;

      if (cleaned === '' || cleaned === '-') {
        this.$emit('input', cleaned === '-' ? '-' : '');
      } else if (matchedRule && matchedRule.name !== 'FRACTION') {
        this.$emit('input', cleaned);
      } else if (cleaned.includes('/')) {
        this.$emit('input', cleaned);
      } else {
        const num = parseFloat(cleaned);
        this.$emit('input', isNaN(num) ? '' : num);
      }
    },

    handleDecimalDigits(val) {
      const actVal = val || this.internalValue;
      let finalValue = actVal.trim();

      if (finalValue === '' || finalValue === '-') {
        return '';
      }

      const num = parseFloat(finalValue);
      if (isNaN(num)) {
        return '';
      }

      let formatted = String(num);
      
      if (!finalValue.includes('.')) {
        formatted = String(Math.floor(num));
      } else {
        const decPart = finalValue.split('.')[1];
        const actualDecimalDigits = decPart.length;
        const displayDecimalDigits = Math.min(actualDecimalDigits, this.decimalDigits);
        formatted = num.toFixed(displayDecimalDigits).replace(/\.?0*$/, '');
      }
      return formatted;
    },

    handleBlur() {
      const val = this.internalValue.trim();
      
      if (val === '') {
        this.oldValue = null;
        this.oldPattern = null;
        this.$emit('input', '');
        this.$emit('blur', '');
        return;
      }

      const upperVal = val.toUpperCase();
      
      for (const rule of this.patternRules) {
        if (rule.pattern.test(upperVal)) {
          this.oldValue = upperVal;
          this.oldPattern = rule;
          this.internalValue = upperVal;
          this.$emit('input', upperVal);
          this.$emit('blur', upperVal);
          return;
        }
      }

      if (val.includes('/')) {
        const parts = val.split('/');
        const validParts = parts.filter(part => part !== '');
        
        if (validParts.length === 0) {
          if (this.oldValue) {
            this.internalValue = this.oldValue;
            this.$emit('input', this.oldValue);
            this.$emit('blur', this.oldValue);
          } else {
            this.internalValue = '';
            this.$emit('input', '');
            this.$emit('blur', '');
          }
          return;
        }
        
        if (validParts.length === 1) {
          const result = validParts[0];
          this.oldValue = result;
          this.oldPattern = this.patternRules.find(r => r.name === 'FRACTION');
          this.internalValue = result;
          this.$emit('input', result);
          this.$emit('blur', result);
          return;
        }
        
        const formattedValue = validParts.join('/');
        this.oldValue = formattedValue;
        this.oldPattern = this.patternRules.find(r => r.name === 'FRACTION');
        this.internalValue = formattedValue;
        this.$emit('input', formattedValue);
        this.$emit('blur', formattedValue);
        return;
      }

      if (this.oldValue && this.oldPattern) {
        const partialMatch = this.oldPattern.inputPattern && this.oldPattern.inputPattern.test(val);
        if (!partialMatch) {
          this.internalValue = this.oldValue;
          this.$emit('input', this.oldValue);
          this.$emit('blur', this.oldValue);
          return;
        }
      }

      let formatted = this.handleDecimalDigits(val);
      this.internalValue = formatted;
      this.$emit('input', parseFloat(formatted));
      this.$emit('blur', parseFloat(formatted));
    }
  }
};
</script>
