<script lang="ts" setup>
import type { HookType } from 'nocodb-sdk'
import { LoadingOutlined } from '@ant-design/icons-vue'
import dayjs from 'dayjs'

const { activeTable } = storeToRefs(useTablesStore())

const { sorts, sortDirection, loadSorts, handleGetSortedData, saveOrUpdate: saveOrUpdateSort } = useUserSorts('Webhook')

const selectedHook = ref<undefined | HookType>()

const { hooks, isHooksLoading } = storeToRefs(useWebhooksStore())

const { loadHooksList, deleteHook: _deleteHook, copyHook, saveHooks } = useWebhooksStore()

const { activeView } = storeToRefs(useViewsStore())

const { t } = useI18n()

const isWebhookModalOpen = ref(false)

const modalDeleteButtonRef = ref(null)

const indicator = h(LoadingOutlined, {
  style: {
    fontSize: '2.5rem',
  },
  spin: true,
})

const deleteHookId = ref('')

const showDeleteModal = ref(false)

const isDeleting = ref(false)

const toBeDeleteHook = computed(() => {
  return hooks.value.find((hook) => hook.id === deleteHookId.value)
})

const deleteHook = async () => {
  isDeleting.value = true
  if (!deleteHookId.value) return

  try {
    await _deleteHook(deleteHookId.value)
  } finally {
    isDeleting.value = false
    showDeleteModal.value = false
    deleteHookId.value = ''
  }
}

const selectedHookId = ref<string | undefined>(undefined)

const isCopying = ref(false)

const copyWebhook = async (hook: HookType) => {
  if (isCopying.value) return

  isCopying.value = true
  try {
    await copyHook(hook)
  } finally {
    isCopying.value = false
  }
}

const openDeleteModal = (hookId: string) => {
  deleteHookId.value = hookId
  showDeleteModal.value = true
}

const webHookSearch = ref('')

const filteredHooks = computed(() =>
  hooks.value.filter((hook) => hook.title?.toLowerCase().includes(webHookSearch.value.toLowerCase())),
)

const sortedHooks = computed(() => {
  return handleGetSortedData(filteredHooks.value, sorts.value)
})

watch(showDeleteModal, () => {
  if (!showDeleteModal.value) return

  nextTick(() => {
    ;(modalDeleteButtonRef.value as any)?.$el?.focus()
  })
})

watch(isWebhookModalOpen, (val) => {
  if (!val) {
    selectedHook.value = undefined
  }
})

watch(
  () => activeTable.value?.id,
  async () => {
    if (!activeTable.value?.id) return

    selectedHookId.value = undefined
    await loadHooksList()
  },
  {
    immediate: true,
  },
)

const toggleHook = async (hook: HookType) => {
  if (hook.event === 'manual' && hook.operation === 'trigger') {
    message.error(t('msg.error.manualTriggerHook'))
    return
  }

  const ogHook = Object.assign({}, hook)
  hook.active = !hook.active
  await saveHooks({ hook, ogHook })
}

const createWebhook = async () => {
  isWebhookModalOpen.value = true
}

const editHook = (hook: HookType) => {
  selectedHook.value = hook
  isWebhookModalOpen.value = true
}

const onModalClose = () => {
  isWebhookModalOpen.value = false
  selectedHook.value = undefined
}

onMounted(async () => {
  loadSorts()
})

const orderBy = computed<Record<string, SordDirectionType>>({
  get: () => {
    return sortDirection.value
  },
  set: (value: Record<string, SordDirectionType>) => {
    // Check if value is an empty object
    if (Object.keys(value).length === 0) {
      saveOrUpdateSort({})
      return
    }

    const [field, direction] = Object.entries(value)[0]

    saveOrUpdateSort({
      field,
      direction,
    })
  },
})

const eventList = ref<Record<string, any>[]>([
  { text: [t('general.on'), t('labels.recordInsert')], value: ['after', 'insert'] },
  { text: [t('general.on'), t('labels.recordUpdate')], value: ['after', 'update'] },
  { text: [t('general.on'), t('labels.recordDelete')], value: ['after', 'delete'] },
  { text: [t('general.onMultiple'), t('labels.recordInsert')], value: ['after', 'bulkInsert'] },
  { text: [t('general.onMultiple'), t('labels.recordUpdate')], value: ['after', 'bulkUpdate'] },
  { text: [t('general.onMultiple'), t('labels.recordDelete')], value: ['after', 'bulkDelete'] },
  { text: [t('general.manual'), t('general.trigger')], value: ['manual', 'trigger'] },
])

const columns: NcTableColumnProps[] = [
  {
    key: 'active',
    title: t('general.active'),
    width: 90,
    minWidth: 90,
  },
  {
    key: 'name',
    title: t('general.name'),
    minWidth: 252,
    showOrderBy: true,
    dataIndex: 'title',
  },
  {
    key: 'type',
    title: t('general.type'),
    basis: '25%',
    minWidth: 200,
    showOrderBy: true,
    dataIndex: 'webhook-operation-type',
  },
  {
    key: 'created_at',
    title: t('labels.addedOn'),
    width: 180,
    minWidth: 180,
    showOrderBy: true,
    dataIndex: 'created_at',
  },
  {
    key: 'action',
    title: '',
    width: 80,
    minWidth: 80,
  },
]

const customRow = (hook: HookType) => {
  return {
    onClick: () => editHook(hook),
  }
}

const getHookTypeText = (hook: HookType) => {
  return (
    eventList.value.find((e) => e.value.includes(hook.event) && e.value.includes(hook.operation))?.text?.join(' ') ||
    `Before ${hook.operation}`
  )
}
</script>

<template>
  <div class="nc-webhook-wrapper w-full p-4">
    <div class="max-w-250 h-full w-full mx-auto">
      <div v-if="activeView && !isHooksLoading">
        <div class="w-full mb-4 flex justify-between gap-3">
          <div class="flex-1 flex gap-2">
            <a-input
              v-model:value="webHookSearch"
              class="w-full nc-input-sm nc-input-border-on-value !max-w-84"
              size="small"
              :placeholder="$t('title.searchWebhook')"
              allow-clear
            >
              <template #prefix>
                <GeneralIcon icon="search" class="mr-2 h-4 w-4 text-gray-500" />
              </template>
            </a-input>
            <NcButton
              class="px-2"
              type="text"
              size="small"
              @click="navigateTo('https://docs.nocodb.com/category/webhook/', { open: navigateToBlankTargetOpenOption })"
            >
              <div class="flex items-center gap-2">
                {{ $t('title.docs') }}

                <GeneralIcon icon="externalLink" />
              </div>
            </NcButton>
          </div>

          <NcButton
            v-e="['c:actions:webhook']"
            type="secondary"
            size="small"
            class="!text-brand-500 !hover:text-brand-600"
            data-testid="nc-new-webhook"
            @click="createWebhook"
          >
            <div class="flex gap-2 items-center">
              <GeneralIcon icon="plus" />
              {{ $t('activity.newWebhook') }}
            </div>
          </NcButton>
        </div>

        <div style="height: calc(100vh - (var(--topbar-height) * 3.5))" class="">
          <div
            v-if="!hooks.length"
            class="flex-col flex items-center gap-6 justify-center w-full h-full py-12 px-4 border-1 rounded-xl border-gray-200"
          >
            <div class="text-gray-700 font-bold text-center text-2xl">{{ $t('msg.createWebhookMsg1') }}</div>
            <div class="text-gray-700 text-center max-w-[24rem]">{{ $t('msg.createWebhookMsg2') }}</div>
            <NcButton v-e="['c:actions:webhook']" class="flex max-w-40" type="primary" size="small" @click="createWebhook">
              <div class="flex items-center gap-2">
                <GeneralIcon icon="plus" class="flex-none" />
                <span>{{ $t('activity.newWebhook') }}</span>
              </div>
            </NcButton>
          </div>

          <NcTable
            v-else
            v-model:order-by="orderBy"
            :columns="columns"
            :data="sortedHooks"
            :custom-row="customRow"
            class="h-full"
            body-row-class-name="nc-view-sidebar-webhook-item"
          >
            <template #bodyCell="{ column, record: hook }">
              <NcTooltip :disabled="hook.event !== 'manual'">
                <template #title>
                  {{ $t('msg.error.manualTriggerHook') }}
                </template>
                <div v-if="column.key === 'active'" v-e="['c:actions:webhook']" @click.stop>
                  <NcSwitch
                    size="small"
                    :disabled="hook.event === 'manual'"
                    :checked="!!hook.active"
                    @change="toggleHook(hook)"
                  />
                </div>
              </NcTooltip>

              <template v-if="column.key === 'name'">
                <NcTooltip class="truncate max-w-full text-gray-800 font-semibold text-sm" show-on-truncate-only>
                  {{ hook.title }}

                  <template #title>
                    {{ hook.title }}
                  </template>
                </NcTooltip>
              </template>
              <template v-if="column.key === 'type'">
                {{ getHookTypeText(hook) }}
              </template>
              <template v-if="column.key === 'created_at'">
                {{ dayjs(hook.created_at).format('DD MMM YYYY') }}
              </template>
              <template v-if="column.key === 'action'">
                <NcDropdown overlay-class-name="nc-webhook-item-action-dropdown">
                  <NcButton type="secondary" size="small" class="!w-8 !h-8" data-testid="nc-webhook-item-action" @click.stop>
                    <component :is="iconMap.threeDotVertical" class="text-gray-700" />
                  </NcButton>
                  <template #overlay>
                    <NcMenu class="w-48">
                      <NcMenuItem key="edit" data-testid="nc-webhook-item-action-edit" @click="editHook(hook)">
                        <GeneralIcon icon="edit" class="text-gray-800" />
                        <span>{{ $t('general.edit') }}</span>
                      </NcMenuItem>
                      <NcMenuItem key="duplicate" data-testid="nc-webhook-item-action-duplicate" @click="copyWebhook(hook)">
                        <GeneralIcon icon="duplicate" class="text-gray-800" />
                        <span>{{ $t('general.duplicate') }}</span>
                      </NcMenuItem>

                      <a-menu-divider class="my-1.5" />

                      <NcMenuItem
                        key="delete"
                        class="!hover:bg-red-50"
                        data-testid="nc-webhook-item-action-delete"
                        @click="openDeleteModal(hook.id)"
                      >
                        <div class="text-red-500">
                          <GeneralIcon icon="delete" class="group-hover:text-accent -ml-0.25 -mt-0.75 mr-0.5" />
                          {{ $t('general.delete') }}
                        </div>
                      </NcMenuItem>
                    </NcMenu>
                  </template>
                </NcDropdown>
              </template>
            </template>
          </NcTable>
        </div>
        <GeneralDeleteModal v-model:visible="showDeleteModal" :entity-name="$t('objects.webhook')" :on-delete="deleteHook">
          <template #entity-preview>
            <div v-if="toBeDeleteHook" class="flex flex-row items-center py-2 px-3 bg-gray-50 rounded-lg text-gray-700 mb-4">
              <component :is="iconMap.hook" class="text-gray-600" />
              <div
                class="capitalize text-ellipsis overflow-hidden select-none w-full pl-2.5"
                :style="{ wordBreak: 'keep-all', whiteSpace: 'nowrap', display: 'inline' }"
              >
                {{ toBeDeleteHook.title }}
              </div>
            </div>
            <span v-if="toBeDeleteHook?.event === 'manual'" class="text-small leading-[18px] mb-2 text-gray-500">
              {{ $t('msg.warning.webhookDelete') }}
            </span>
          </template>
        </GeneralDeleteModal>

        <Webhook
          v-if="isWebhookModalOpen"
          v-model:value="isWebhookModalOpen"
          :hook="selectedHook"
          :event-list="eventList"
          @close="onModalClose"
        />
      </div>
      <div
        v-else
        class="h-full w-full flex flex-col justify-center items-center"
        style="height: calc(100vh - (var(--topbar-height) * 2))"
      >
        <a-spin size="large" :indicator="indicator" />
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
:deep(.ant-input::placeholder) {
  @apply text-gray-500;
}
</style>
