<template>
  <div class="property-widget">
    <!-- Boolean type - checkbox -->
    <v-checkbox
      v-if="descriptor?.propertyType === 'Boolean'"
      :model-value="modelValue"
      :disabled="disabled"
      hide-details
      density="compact"
      @update:model-value="$emit('update:modelValue', $event)"
    />

    <!-- Array type - multiple widgets -->
    <div v-else-if="descriptor?.array">
      <div
        v-for="(item, index) in modelValue || []"
        :key="String(index)"
        class="d-flex align-center mb-2"
      >
        <PropertyWidget
          :model-value="item"
          :descriptor="{ ...descriptor, array: false }"
          :disabled="disabled"
          class="flex-grow-1"
          @update:model-value="updateArrayItem(Number(index), $event)"
        />

        <div class="d-flex flex-column ml-2">
          <v-btn
            icon="mdi-chevron-up"
            size="x-small"
            variant="text"
            :disabled="disabled || index === 0"
            @click="moveUp(Number(index))"
          />
          <v-btn
            icon="mdi-chevron-down"
            size="x-small"
            variant="text"
            :disabled="disabled || index === (modelValue?.length || 0) - 1"
            @click="moveDown(Number(index))"
          />
        </div>

        <v-btn
          icon="mdi-close"
          size="x-small"
          variant="text"
          color="error"
          :disabled="disabled"
          class="ml-1"
          @click="removeItem(Number(index))"
        />
      </div>

      <v-btn
        prepend-icon="mdi-plus"
        size="small"
        variant="outlined"
        :disabled="disabled"
        @click="addItem"
      >
        Добавить
      </v-btn>
    </div>

    <!-- Text type -->
    <v-textarea
      v-if="descriptor?.propertyType === 'Text' && stringConstraint?.multiline"
      :model-value="modelValue"
      :disabled="disabled"
      :rules="textValidationRules"
      density="compact"
      variant="outlined"
      :maxlength="stringConstraint?.maxLength"
      rows="3"
      auto-grow
      @update:model-value="$emit('update:modelValue', $event)"
    />

    <v-text-field
      v-else-if="descriptor?.propertyType === 'Text'"
      :model-value="modelValue"
      :disabled="disabled"
      :rules="textValidationRules"
      density="compact"
      variant="outlined"
      :maxlength="stringConstraint?.maxLength"
      @update:model-value="$emit('update:modelValue', $event)"
    />

    <!-- Number type -->
    <div v-else-if="descriptor?.propertyType === 'Number'">
      <!-- Range slider for numbers with step > 0 -->
      <v-slider
        v-if="useSlider"
        :model-value="modelValue"
        :disabled="disabled"
        hide-details
        density="compact"
        :min="numberConstraint?.min"
        :max="numberConstraint?.max"
        :step="numberConstraint?.step"
        @update:model-value="$emit('update:modelValue', $event)"
      >
        <template #append>
          <v-text-field
            :model-value="modelValue"
            :disabled="disabled"
            hide-details
            density="compact"
            variant="outlined"
            style="width: 100px"
            type="number"
            :min="numberConstraint?.min"
            :max="numberConstraint?.max"
            :step="numberConstraint?.step"
            @update:model-value="$emit('update:modelValue', $event)"
          />
        </template>
      </v-slider>

      <!-- Text field for other numbers -->
      <v-text-field
        v-else
        :model-value="modelValue"
        :disabled="disabled"
        hide-details
        density="compact"
        variant="outlined"
        type="number"
        :min="numberConstraint?.min"
        :max="numberConstraint?.max"
        :step="numberConstraint?.step || (numberConstraint?.integer ? 1 : 0.1)"
        @update:model-value="$emit('update:modelValue', $event)"
      />
    </div>

    <!-- ValueList type - dropdown -->
    <v-select
      v-else-if="descriptor?.propertyType === 'ValueList'"
      :model-value="modelValue"
      :disabled="disabled"
      hide-details
      density="compact"
      variant="outlined"
      :items="valueListConstraint?.values || []"
      item-title="label"
      item-value="value"
      @update:model-value="$emit('update:modelValue', $event)"
    />

    <!-- JSON type - textarea -->
    <v-textarea
      v-else-if="descriptor?.propertyType === 'JSON'"
      :model-value="
        typeof modelValue === 'object' ? JSON.stringify(modelValue, null, 2) : modelValue
      "
      :disabled="disabled"
      hide-details
      density="compact"
      variant="outlined"
      rows="5"
      @update:model-value="updateJsonValue"
    />

    <!-- Fallback for unknown types -->
    <v-text-field
      v-else
      :model-value="modelValue"
      :disabled="disabled"
      hide-details
      density="compact"
      variant="outlined"
      placeholder="Unknown type"
      @update:model-value="$emit('update:modelValue', $event)"
    />
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import type {
  PropertyDescriptor,
  NumberConstraint,
  ValueListConstraint,
  StringConstraint
} from '@/generated/RpcClient'

interface Props {
  modelValue: any
  descriptor?: PropertyDescriptor
  disabled?: boolean
}

interface Emits {
  (e: 'update:modelValue', value: any): void
}

const props = defineProps<Props>()
const emit = defineEmits<Emits>()

const stringConstraint = computed((): StringConstraint | undefined => {
  return props.descriptor?.constraints?.find(
    (c) => c.type === 'StringConstraint'
  ) as StringConstraint
})

const numberConstraint = computed((): NumberConstraint | undefined => {
  return props.descriptor?.constraints?.find(
    (c) => c.type === 'NumberConstraint'
  ) as NumberConstraint
})

const valueListConstraint = computed((): ValueListConstraint | undefined => {
  return props.descriptor?.constraints?.find(
    (c) => c.type === 'ValueListConstraint'
  ) as ValueListConstraint
})

const useSlider = computed((): boolean => {
  const constraint = numberConstraint.value
  return constraint ? constraint.step > 0 : false
})

const textValidationRules = computed(() => {
  const rules: any[] = []

  if (stringConstraint.value?.regexp) {
    const regex = new RegExp(stringConstraint.value.regexp)
    rules.push((value: string) => {
      if (!value) return true // Allow empty values
      return regex.test(value) || 'Значение не соответствует требуемому формату'
    })
  }

  return rules
})

const updateJsonValue = (newValue: string) => {
  try {
    if (!newValue.trim()) {
      emit('update:modelValue', null)
      return
    }
    const parsed = JSON.parse(newValue)
    emit('update:modelValue', parsed)
  } catch (e) {
    // Keep invalid JSON as string for now
    emit('update:modelValue', newValue)
  }
}

const updateArrayItem = (index: number, newValue: any) => {
  const newArray = [...(props.modelValue || [])]
  newArray[index] = newValue
  emit('update:modelValue', newArray)
}

const addItem = () => {
  const newArray = [...(props.modelValue || [])]

  // Determine default value based on property type
  let defaultValue: any = ''
  if (props.descriptor?.propertyType === 'Boolean') {
    defaultValue = false
  } else if (props.descriptor?.propertyType === 'Number') {
    defaultValue = 0
  } else if (props.descriptor?.propertyType === 'JSON') {
    defaultValue = {}
  }

  newArray.push(defaultValue)
  emit('update:modelValue', newArray)
}

const removeItem = (index: number) => {
  const newArray = [...(props.modelValue || [])]
  newArray.splice(index, 1)
  emit('update:modelValue', newArray)
}

const moveUp = (index: number) => {
  if (index === 0) return
  const newArray = [...(props.modelValue || [])]
  const temp = newArray[index]
  newArray[index] = newArray[index - 1]
  newArray[index - 1] = temp
  emit('update:modelValue', newArray)
}

const moveDown = (index: number) => {
  const array = props.modelValue || []
  if (index === array.length - 1) return
  const newArray = [...array]
  const temp = newArray[index]
  newArray[index] = newArray[index + 1]
  newArray[index + 1] = temp
  emit('update:modelValue', newArray)
}
</script>

<style scoped>
.property-widget {
  width: 100%;
}
</style>
