<template>
  <div class="prvi field-render">
    <table v-if="!noFieldsAdded" class="table-sm table-striped w-100 table-key-value mb-2">
      <tbody>
        <template v-for="field in fields">
          <template v-for="(item, index) in getNormalizedFieldData(field)">
            <tr :key="`${field.id}-${index}`" :class="{ 'field-multiple': field.allowMultiple, 'field-children': field.children && field.children.length > 0 }">
              <td class="field-title text-secondary">
                <span :class="getFieldIconClass(field.type)"></span>
                {{ field.title }}{{ field.allowMultiple ? ` #${index + 1}` : '' }}
              </td>
              <td :class="{ 'text-right': ['number', 'boolean'].includes(field.type), 'field-value': true }">
                <FieldContent 
                  :field="field" 
                  :value="getFieldValue(field, index)" 
                  :mode="mode"
                  @update="updateFieldValue(field.id, index, $event)"
                />
              </td>
              <td v-if="mode === FieldRenderMode.Edit && field.readonly !== true" style="width: 1%;">
                <a href="javascript:;" @click="deleteFieldItem(field.id, index)">
                  <span class="mdi mdi-delete text-danger"></span>
                </a>
              </td>
            </tr>
          </template>
        </template>
      </tbody>
    </table>
    <div v-else-if="mode !== FieldRenderMode.Edit">
      <p>No fields added</p>
    </div>

    <div v-if="mode === FieldRenderMode.Edit && hadFieldsToAdd" class="alert alert-info mb-3">
      <div class="d-flex align-items-center flex-nowrap">
        <label class="form-label mb-0 me-2 text-nowrap pr-3">Add field</label>
        <select class="custom-select form-select flex-grow-1" v-model="newFieldId">
          <option value="-">-</option>
          <template v-for="field in fields">
            <option v-if="canAddField(field)" :key="field.id" :value="field.id">{{ field.title }}</option>
          </template>
        </select>
      </div>

      <div v-if="newFieldData" class="mt-2">
        <FieldContent 
          :field="newFieldData" 
          :value="newFieldValue" 
          :mode="FieldRenderMode.Edit"
          @update="updateNewFieldValue"
        />
      </div>
    </div>

    <a v-if="mode === FieldRenderMode.None" :class="editButtonClass" href="javascript:;" @click="mode = FieldRenderMode.Edit">
      <span class="mdi mdi-pencil" />
      {{ editButtonText }}
    </a>

    <a v-if="mode === FieldRenderMode.Edit" class="btn btn-primary btn-sm mr-1" href="javascript:;" @click="save">
      <span class="mdi mdi-check" /> OK
    </a>

    <a v-if="mode === FieldRenderMode.Edit" class="btn btn-secondary btn-sm" href="javascript:;" @click="cancelSave">
      Cancel
    </a>
</div>
</template>

<script lang="ts">
import { defineComponent, PropType } from 'vue'
import { keyValueTableFields } from '@/types'
import FieldEditRender from './edit.vue'
import FieldDisplayRender from './display.vue'
import FieldContent from './content.vue'
import { convertValueToType } from './utils'

enum FieldRenderMode {
  None = 'none',
  Edit = 'edit',
} 

export default defineComponent({
  components: {
    FieldEditRender,
    FieldDisplayRender,
    FieldContent
  },
  props: { 
    fields: {
      type: Array as PropType<typeof keyValueTableFields>,
      required: true,
    },
    value: {
      type: Object as PropType<Record<string, string | number | Record<string, string | number> | any[]>>,
      required: false,
      default: () => ({}),
    },
  },
  data() {
    return {
      FieldRenderMode,
      internalValue: {} as any,
      mode: FieldRenderMode.None,
      newFieldId: '-',
      newFieldValue: {} as any,
    }
  },
  watch: {
    value: {
      handler(newVal) {
        this.mapExternalValue(newVal)
      },
      immediate: true,
    },
  },
  computed: {
    newFieldData() {
      return this.fields.find(field => field.id === this.newFieldId)
    },
    hadFieldsToAdd() {
      return this.fields.some(field => this.canAddField(field))
    },
    noFieldsAdded() {
      return Object.keys(this.internalValue).length === 0
    },
    getFieldIconClass() {
      return (fieldType: string) => ({
        'mdi': true,
        'mdi-format-text': fieldType === 'text',
        'mdi-numeric': fieldType === 'number',
        'mdi-calendar': fieldType === 'date',
        'mdi-checkbox-marked-circle-outline': fieldType === 'boolean',
        'mdi-palette': fieldType === 'color',
        'mdi-format-list-bulleted': fieldType === 'select'
      })
    },
    editButtonClass() {
      return {
        'btn': true,
        'btn-secondary': !this.noFieldsAdded,
        'btn-sm': true,
        'mr-1': true,
        'btn-primary': this.noFieldsAdded
      }
    },
    editButtonText() {
      return this.noFieldsAdded ? 'Add fields' : 'Edit'
    }
  },
  methods: {
    getNormalizedFieldData(field: any) {
      if (field.allowMultiple) {
        return Array.isArray(this.internalValue[field.id]) 
          ? this.internalValue[field.id] 
          : [];
      } else {
        return typeof this.internalValue[field.id] !== 'undefined' 
          ? [this.internalValue[field.id]] 
          : [];
      }
    },
    
    getFieldValue(field: any, index: number) {
      if (field.allowMultiple) {
        return this.internalValue[field.id][index];
      } else {
        return this.internalValue[field.id];
      }
    },
    
    canAddField(field: any) {
      if (field.allowMultiple) {
        // For allowMultiple fields, we can always add more items
        return true
      } else {
        // For single fields, only if not already added
        return typeof this.internalValue[field.id] === 'undefined'
      }
    },
    mapExternalValue(value: any) {
      if (value && (typeof value === 'object' || Array.isArray(value))) {
        // Create a new object to ensure Vue reactivity
        this.internalValue = JSON.parse(JSON.stringify(value))
      } else {
        this.internalValue = {}
      }
    },
    updateFieldValue(fieldId: string, index: number, value: any) {
      const field = this.fields.find(f => f.id === fieldId);
      if (field && field.allowMultiple) {
        this.$set(this.internalValue[fieldId], index, value);
      } else {
        this.$set(this.internalValue, fieldId, value);
      }
    },
    updateNewFieldValue(value: any) {
      this.newFieldValue = value
    },
    deleteFieldItem(fieldId: string, index: number) {
      const field = this.fields.find(f => f.id === fieldId);
      if (field && field.allowMultiple) {
        this.deleteMultipleFieldItem(fieldId, index);
      } else {
        this.deleteField(fieldId);
      }
    },
    deleteField(id: string) {
      // Use Vue.set or spread operator to ensure reactivity
      const newValue = { ...this.internalValue }
      delete newValue[id]
      this.internalValue = newValue
    },
    deleteMultipleFieldItem(fieldId: string, index: number) {
      if (Array.isArray(this.internalValue[fieldId])) {
        this.internalValue[fieldId].splice(index, 1)
        // If no more items, remove the field entirely
        if (this.internalValue[fieldId].length === 0) {
          delete this.internalValue[fieldId]
        }
      }
    },
    save() {
      let tempValue: any = {}
      console.log('Saving', this.internalValue)

      for (const field of this.fields) {
        if (typeof this.internalValue[field.id] !== 'undefined') {
          if (field.allowMultiple && Array.isArray(this.internalValue[field.id])) {
            // For allowMultiple fields, convert each item in the array
            tempValue[field.id] = this.internalValue[field.id].map((item: any) => 
              convertValueToType(item, field.type)
            )
          } else {
            tempValue[field.id] = convertValueToType(this.internalValue[field.id], field.type)
          }
        }
      }

      if (this.newFieldId !== '-') {
        const field = this.fields.find(f => f.id === this.newFieldId)
        if (field && field.allowMultiple) {
          // For allowMultiple fields, add to existing array or create new array
          if (!tempValue[this.newFieldId]) {
            tempValue[this.newFieldId] = []
          }
          tempValue[this.newFieldId].push(this.newFieldValue)
        } else {
          tempValue[this.newFieldId] = this.newFieldValue
        }
        this.newFieldId = '-'
        this.newFieldValue = {}
      }

      this.$emit('input', tempValue)
      this.mode = FieldRenderMode.None
    },
    cancelSave() {
      this.mapExternalValue(this.value)
      this.mode = FieldRenderMode.None
    },
  },
})
</script>

<style lang="scss" scoped>
.field {
  width: 100%;
}

.field-title {
  width: 50%;
}

.field-value {
  font-weight: 500;
}

.text-right {
  input {
    text-align: right;
  }
}
</style>
