<template>
  <div class="container key-value-table mw-100">
    <label :for="'toDo' + _uid">{{ caption }}</label>
    <h3 v-if="title" class="text-muted">{{ title }}</h3>
    <p v-if="subtitle" class="text-muted mt-2 subtitle">{{ subtitle }}</p>

    <table class="table-sm table-striped w-100 table-key-value">
      <thead v-show="computedValue.length" class="">
        <tr>
          <th v-for="(field, index) in fields" :key="`k-${index}`" :class="field.class ? field.class : 'col-5'">{{ field.label }}</th>
          <th class="col-1">&nbsp;</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(item, index) in computedValue" :key="index">
          <td class="align-middle"> {{ searchable ? item.key : lookUpTextInOptions(item.key) }}</td>
          <td v-if="secondList" class="align-middle"> {{ lookUpTextInSecondOptions(item.option) }}</td>
          <td v-if="valueInput && useTimestamp" class="align-middle"> {{ formatTimestampToDate(item.value) }}</td>
          <td v-else-if="valueInput" class="align-middle"> {{ formatValue(item.value) }}</td>
          <td>
            <button type="button" :class="!editMode ? 'invisible' : ''" class="btn btn-sm w-100 btn-outline-danger" @click="handleDelete(index)"><span class="mdi mdi-close fs-5"></span></button>
          </td>
        </tr>
        <tr v-if="editMode">
          <td v-if="searchable" class="align-top">
            <Search v-model="selectedOption" :dataset="searchDataset" :placeholder="placeholder" :clear="clearSearch" @clear="switchClear" @input="searchAnswered = !(selectedOption === null)" />
          </td>
          <td v-else class="align-top">
            <select v-model="selectedOption" class="form-select form-control">
              <option selected disabled>{{ placeholder }}</option>
              <option v-for="(option, i) in options" :key="i" :value="option.value" :disabled="isDisabled(option)" :class="{'custom-disabled': isDisabled(option)}">{{ option.text }}</option>
            </select>
          </td>
          <td v-if="secondList" class="align-top">
            <select v-model="secondSelectedOption" class="form-select form-control">
              <option selected disabled>{{ secondPlaceholder }}</option>
              <option v-for="(option, i) in secondOptions" :key="i" :value="option.value">{{ option.text }}</option>
            </select>
          </td>
          <td v-if="valueInput || selectedOption !== emptyValueKey" class="align-top">
            <input v-if="inputType != 'date'" v-model="addInput" :type="inputType" class="form-control" />
            <input-date v-else v-model="addInput" :use-timestamp="useTimestamp" />
          </td>
          <td class="align-top">
            <button class="btn btn-outline-success w-100" type="button" :disabled="emptyField" @click="handleAdd"><span class="mdi mdi-plus fs-5"></span></button>
          </td>
        </tr>
      </tbody>
    </table>

    <div v-show="noValuesText && ! computedValue.length && ! editMode">
      {{ noValuesText }}
    </div>

    <div v-if="editable" class="mt-2">
      <a class="btn btn-primary btn-sm me-4 me-md-2" href="javascript:;" @click="toggleMode">
        <span class="mdi mdi-pencil" /> {{ editMode ? saveText : editText }}
      </a>

      <a v-if="editMode" class="btn btn-secondary btn-sm ml-1" href="javascript:;" @click="cancelAndToggleMode">
        {{ cancelText }}
      </a>
    </div>

    <small class="form-text text-muted">
      {{ description }}
    </small>
  </div>
</template>

<script>
import inputDate from './Date.vue'
import Search from './Search.vue'
import { formatTimestampToDate } from '../../tools/util'

export default {
  components: {
    inputDate,
    Search
  },
  props: {
    caption: { type: String, default: '' },
    description: { type: String, default: '' },
    title: { type: String, default: '' },
    subtitle: { type: String, default: ''},
    noValuesText: { type: String, default: '' },
    placeholder: { type: String, default: 'Select option' },
    keyValue: { type: Boolean, default: true },
    value: { type: [Array, Object], required: true, default: () => [] },
    fields: { type: Array, required: true, default: () => [] },
    options: { type: Array, required: false, default: () => [] }, 
    editable: { type: Boolean, default: true },
    secondList: { type: Boolean, default: false },
    secondOptions: { type: Array, default: () => [] },
    secondPlaceholder: { type: String, default: 'Select option' },
    inputType: { type: String, default: 'text' },
    editText: { type: String, default: 'Edit'},
    saveText: { type: String, default: 'Save'},
    cancelText: { type: String, default: 'Cancel'},
    searchable: { type: Boolean, default: false },
    searchDataset: { type: Object, default: () => {}},
    valueInput: { type: Boolean, default: true },
    emptyValueKey: { type: String, default: ''},
    useTimestamp:{ type: Boolean, default: false },
    valueFormatter: { 
      type: Function, 
      default: null 
    }
  },
  data() {
    return {
      selectedOption: null,
      secondSelectedOption: null,
      addInput: null,
      localVal: [],
      computedValue: [],
      editMode: false,
      clearSearch: false,
      searchAnswered: true,
      oldValues: {}
    }
  },
  computed: {
    emptyField() {
      const vm = this
      return (vm.addInput || !vm.valueInput || vm.emptyValueKey === vm.selectedOption) && (vm.selectedOption !== vm.placeholder) && (!vm.searchable || vm.searchAnswered) && !vm.isSecondEmpty ? false : true
    },
    isSecondEmpty() {
      const vm = this
      if(vm.secondList) {
        if(vm.secondSelectedOption !== vm.secondPlaceholder) {
          return false
        }
        return true
      }
      return false
    },
    filledPartially() {
      const vm = this
      if(!vm.emptyField) return false
      if(vm.valueInput && vm.addInput) return true
      if(!vm.searchable && (vm.selectedOption != vm.placeholder)) return true
      if(vm.searchable && vm.searchAnswered) return true
      if(vm.secondList && (vm.secondSelectedOption != vm.secondPlaceholder)) return true
      return false
    }
  },
  mounted() {
    const vm = this
    if(vm.options && !vm.searchable) {
      vm.selectedOption = vm.placeholder
    } else if(vm.searchable) {
      vm.selectedOption = null
    }
    vm.secondSelectedOption = vm.secondPlaceholder
    vm.localVal = vm.localVal != undefined ? JSON.parse(JSON.stringify(vm.value)) : []
    if(!vm.keyValue && vm.secondList) {
      let keys = Object.keys(vm.localVal)
      keys.forEach((el) => {
        let splitKey = el.split('-')
        let tempObject = {}
        tempObject.key = splitKey[0]
        tempObject.option = splitKey[1]
        if(vm.valueInput) {
          tempObject.value = vm.localVal[el]
        }
        if(vm.searchable) {
          if(vm.lookUpTextInSearchDataset(tempObject.key) && vm.lookUpTextInSecondOptions(tempObject.option)) {
            vm.computedValue.push(tempObject)
          }
        } else if(vm.lookUpTextInOptions(tempObject.key) && vm.lookUpTextInSecondOptions(tempObject.option)) {
          vm.computedValue.push(tempObject)
        }
      })
    } else if(!vm.keyValue) {
      let keys = Object.keys(vm.localVal)
      keys.forEach(el => {
        let tempObject = {}
        tempObject.key = el
        if(vm.valueInput) {
          tempObject.value = vm.localVal[el]
        }
        if(vm.searchable) {
          if(vm.lookUpTextInSearchDataset(tempObject.key)) {
            vm.computedValue.push(tempObject)
          }
        } else if(vm.lookUpTextInOptions(tempObject.key)) {
          vm.computedValue.push(tempObject)
        }
      })
    } else {
      vm.computedValue = vm.localVal
    }
    vm.oldValues = JSON.parse(JSON.stringify(vm.computedValue))
    this.$emit('table-elements-updated', this.getTableElements());
  },
  methods: {
    handleAdd() {
      const vm = this
      if(!vm.emptyField) {
        let temp = {}
        
        temp = {
          key: vm.selectedOption,
        }
        if(vm.valueInput) {
          temp.value = vm.convertToFloatIfApplicable(vm.addInput);
        }
        if(vm.secondList) {
          temp = {
            ...temp,
            option: vm.secondSelectedOption
          }
          vm.secondSelectedOption = vm.secondPlaceholder
        }
        vm.computedValue.push(temp)

        vm.addInput = null;
        if(vm.searchable) {
          vm.selectedOption = null
        } else {
          vm.selectedOption = vm.placeholder;
        }
        vm.clearSearch = true
      }
      this.$emit('table-elements-updated', this.getTableElements());
    },
    convertToFloatIfApplicable(value) {
      // Attempt to convert a string to a float if it's numeric
      const floatValue = parseFloat(value);
      return !isNaN(floatValue) && isFinite(value) ? floatValue : value;
    },
    handleDelete(index) {
      const vm = this
      vm.computedValue.splice(index, 1)
      this.$emit('table-elements-updated', this.getTableElements());
    },
    getTableElements() {
      return this.computedValue.map(item => ({
        label: this.searchable ? item.key : this.lookUpTextInOptions(item.key),
        value: item.value,
        ...(this.secondList && { secondLabel: this.lookUpTextInSecondOptions(item.option) }),
      }));
    },
    isDisabled(option) {
      const vm = this
      return vm.computedValue.find(el => el.key == option.value)
    },
    lookUpTextInOptions(value) {
      if(!this.options) return false
      let opt = this.options.find(option => option.value == value)
      return opt ? opt.text : false
    },
    lookUpTextInSecondOptions(value) {
      if(!this.secondOptions) return false
      let opt = this.secondOptions.find(option => option.value == value)
      return opt ? opt.text : false
    },
    lookUpTextInSearchDataset(value) {
      if(!this.searchDataset) return false
      return this.searchDataset[value] ? true : false
    },
    toggleMode() {
      const vm = this
      if(vm.filledPartially && vm.editMode) {
        vm.$emit('hasError')
        return;
      }
      vm.editMode = vm.editable ? !vm.editMode : false
      if(!vm.editMode) {
        if(!vm.emptyField) {
          vm.handleAdd()
        } else {
          if(vm.options && !vm.searchable) {
            vm.selectedOption = vm.placeholder
          } else {
            vm.selectedOption = null
          }
          if(vm.secondPlaceholder) {
            vm.secondSelectedOption = vm.secondPlaceholder
          }
          if(vm.valueInput) {
            vm.addInput = null
          }
        }
        let output;
        if(vm.keyValue) {
          output = JSON.parse(JSON.stringify(vm.computedValue))
        } else {
          output = {}
          if(vm.secondList) {
            vm.computedValue.forEach((item) => {
              if(item.option && item.key) {
                output[`${item.key}-${item.option}`] = item.value ? item.value : null
              }
            })
          } else {
            vm.computedValue.forEach((item) => {
              if(item.key) {
                output[`${item.key}`] = item.value ? item.value : null
              }
            })
          }
        }
        vm.oldValues = JSON.parse(JSON.stringify(vm.computedValue))
        vm.$emit('input', output)
        setTimeout(() => {
          vm.$emit('save')
        }, 0)
      } else {
        if(vm.searchable) {
          vm.selectedOption = null
        }
        if(vm.secondPlaceholder) {
          vm.secondSelectedOption = vm.secondPlaceholder
        }
        if(vm.valueInput) {
          vm.addInput = null
        }
      }
    },
    switchClear(val) {
      const vm = this
      vm.clearSearch = false
    },
    cancelAndToggleMode() {
      const vm = this
      vm.editMode = false
      if(vm.options && !vm.searchable) {
        vm.selectedOption = vm.placeholder
      } else {
        vm.selectedOption = null
      }
      if(vm.secondPlaceholder) {
        vm.secondSelectedOption = vm.secondPlaceholder
      }
      vm.computedValue = JSON.parse(JSON.stringify(vm.oldValues))
    },
    formatTimestampToDate(timestamp) {
      return formatTimestampToDate(timestamp);
    },
    formatValue(value) {
      if (this.valueFormatter) {
        return this.valueFormatter(value);
      }
      return value;
    },
  }
}
</script>

<style lang="scss" scoped>
.table-key-value {
  // background-color: #f8f8f8;
  border-radius: 3px;
}

.micro-input-date {
  margin-bottom: 0px !important;
}

.custom-disabled {
  color: #AEB5BC;
}
</style>
