<template>
  <div
    class="search"
    :key="parentStore.item"
    @change.prevent.stop=""
  >
    <header class="search__header">{{ collectionName }}</header>
    <div v-if="isExpanded" class="flex flex-col gap-y-2">
      <sv-form
        v-bind="{
          collection,
          form: store.fields,
          formData: edited,
          itemIndex,
          fieldIndex
        }"
      ></sv-form>
      <div class="flex gap-x-1" v-if="!expand">
        <sv-button @clicked="insert">Salvar</sv-button>
        <sv-button @clicked="clear">Limpar</sv-button>
      </div>
    </div>

    <div v-else class="flex flex-wrap gap-2">
      <!-- field.purge deprecated ? -->
      <sv-form
        v-bind="{
          form: store.useFields(indexes),
          formData: inputValue,
          collection: field.collection
        }"
        @input="lazySearch"
      ></sv-form>
      <sv-button
        v-if="expanded && array"
        icon="plus"
        @clicked="addItem"
      >
        Novo
      </sv-button>
    </div>

    <div v-if="!isExpanded || array" :key="inputValue">
      <div v-if="selected.length > 0">
        <div
          v-for="(item, index) in selected"
          :key="`item-${index}`"
          class="search__item"
        >
          <div class="flex-1">{{ item[indexes[0]] }}</div>

          <div v-if="!searchOnly" class="search__icons">
            <sv-bare-button @clicked="edit(item)">
              <sv-icon
                name="edit"
                fill="gray"
              ></sv-icon>
            </sv-bare-button>
            <sv-bare-button @clicked="unselect(item)">
              <sv-icon
                name="trash"
                fill="gray"
              ></sv-icon>
            </sv-bare-button>
          </div>

          <div v-else>
            <sv-bare-button @clicked="unselect(item, false)">
              <sv-icon name="minus" fill="gray"></sv-icon>
            </sv-bare-button>
          </div>
        </div>
      </div>

      <div :class="`select-none ${store.isLoading ? 'opacity-30' : 'opacity-60'}`" v-if="!isExpanded">
        <div v-if="store.items.length || selected.length">
          <div
            v-for="(item, index) in store.items"
            :key="`item-${index}`"
            class="search__item"
            @click="select(item)"
          >
            <div>{{ item[indexes[0]] }}</div>
            <div class="search__icons">
              <sv-icon
                name="plus"
                fill="gray"
              ></sv-icon>
            </div>
          </div>
        </div>
        <div v-else class="p-2 text-sm">
          <div v-if="isTyping">
            Pesquisando...
          </div>
          <div v-else-if="!store.isLoading && Object.values(inputValue).filter((v) => !!v).length > 0">
            Não há resultados
          </div>
        </div>
      </div>

    </div>
  </div>
</template>

<script setup lang="ts">
import {
  provide,
  inject,
  computed,
  ref,
  reactive,
  defineAsyncComponent,
  onMounted

} from 'vue'

import { useStore, useParentStore } from '@savitri/web'
import {
  SvButton,
  SvBareButton,
  SvIcon

} from '../..'

const SvForm = defineAsyncComponent(() => import('../../molecules/sv-form/sv-form.vue'))

type Props = {
  modelValue: any
  propName: string
  collection; string
  field: any
  itemIndex?: number
  indexes: any
  activeOnly?: boolean
  searchOnly?: boolean
}

const props = defineProps<Props>()

const emit = defineEmits<{
  (e: 'update:modelValue', event: any): void
  (e: 'changed'): void
}>()


const searchOnly = inject<boolean>('searchOnly', props.searchOnly)

const parentStore = useParentStore(props.collection)
const store = useStore(props.field.collection)

provide('iconReactive', true)

onMounted(() => store.clearItems())

const field = props.field
const expanded = ref<boolean>(false)
const edited = ref<any>(parentStore.item[props.propName])

const collection = computed(() => field.collection)
const expand = computed(() => field.expand === true)
const array = computed(() => field.array)

const collectionName = computed(() => (field.label||'').capitalize())
const isExpanded = computed(() => expanded.value || field.expand)

const rawItem = computed(() => {
  const item = parentStore.item[props.propName]
  const items = field.array
    ? (Array.isArray(item) ? item : [item])
    : item

  return items
})

const isTyping = ref(false)
const inputValue = reactive({})

const selected = computed(() => {
  const options = props.modelValue
  const selected = field.array
    ? Array.isArray(options) ? options : [options]
    : (Object.keys(options||{}).length > 0 ? [options] : [])

  return selected
    .filter((option: { _id: string }) => !!option?._id)
})

const fieldIndex = ref(0)

const insert = async () => {
  const result: any = await store.insert({ what: edited.value })

  const value = (() => {
    if( !array.value ) {
      return result
    }

    const selected = rawItem.value
      .filter(({ _id }: { _id: string }) => !!_id && result._id !== _id)

    return [
      ...selected,
      result
    ]
  })()

  const parentResult = await parentStore.insert({
    what: {
      ...(parentStore.item._id ? { _id: parentStore.item._id } : parentStore.item),
      [props.propName]: value
    }
  })

  emit('update:modelValue', parentResult[props.propName])
  store.clearItems()
  expanded.value = false
}

const edit = (item: any) => {
  const itemsCount = rawItem.value.length
  fieldIndex.value = parentStore.getItemIndex(item._id, selected.value)

  edited.value = item
  expanded.value = true
}

const clear = () => {
  expanded.value = false
  store.clearItems()
  if( array.value ) {
    rawItem.value = rawItem.value.slice(0, -1)
  }
}

const select = (item: any) => {
  const filterEmpties = (array: Array<any>) => array.filter(e => typeof e !== 'object' || Object.keys(e).length > 0)
  const modelValue = array.value
    ? filterEmpties(Array.isArray(props.modelValue) ? props.modelValue : [props.modelValue])
    : props.modelValue

  store.clearItems()
  emit('update:modelValue', array.value
    ? [ ...modelValue, item ]
    : item
  )

  emit('changed')
}

const unselect = async (item: any, purge=true) => {
  if( props.field.purge && purge ) {
    const { _id } = item
    await store.remove({ payload: { filter: { _id } }})
  }

  emit('update:modelValue', array.value
      ? props.modelValue.filter((option: any) => option._id !== item._id)
      : undefined
  )
}

const addItem = () => {
  fieldIndex.value = selected.value.length + 1

  edited.value = {}
  expanded.value = true
}

const search = () => {
  if( Object.values(inputValue).every((v: string) => v.length === 0) ) {
    store.clearItems()
    return
  }

  if( store.isLoading ) {
    return
  }

  store.getAll({
    limit: 5,
    filters: {
      ...(props.activeOnly ? { active: true } : {}),
      $or: props.indexes
      .filter((i: string) => inputValue[i]?.length > 0)
      .map((i: string) => ({
        [i]: {
          $regex: inputValue[i].trim(),
          $options: 'i'
        }
      }))
    }
  })
}

declare global {
  interface Window {
    __lazySearchTimeout: any
  }
}

const lazySearch = () => {
  isTyping.value = true
  window.clearTimeout(window.__lazySearchTimeout)
  window.__lazySearchTimeout = setTimeout(() => {
    search()
    isTyping.value = false
  }, 800)
}
</script>

<style scoped src="./sv-search.scss"></style>
