<script setup lang="ts">
import type { SourceType, TableType } from 'nocodb-sdk'

defineProps<{
  baseId: string
}>()

defineEmits(['createTable'])

const { $e } = useNuxtApp()

const { api } = useApi()

const basesStore = useBases()

const { isUIAllowed } = useRoles()

const { refreshCommandPalette } = useCommandPalette()

const { refreshViewTabTitle } = useViewsStore()

const { activeTable, baseTables } = storeToRefs(useTablesStore())

const { isSharedBase } = storeToRefs(useBase())

const { loadProject } = basesStore

const { setMenuContext } = inject(TreeViewInj)!

const isExpanded = ref(true)

const activeKey = ref<string[]>([])

const filterQuery = ref('')

const keys = ref<Record<string, number>>({})

const isBasesOptionsOpen = ref<Record<string, boolean>>({})

const sourceRenameHelpers = ref<
  Record<
    string,
    {
      editMode: boolean
      tempTitle: string
    }
  >
>({})

const [searchActive] = useToggle()

const base = inject(ProjectInj)!

const baseRole = computed(() => base.value.project_role || base.value.workspace_role)

const enableEditModeForSource = (sourceId: string) => {
  if (!isUIAllowed('baseRename')) return

  const source = base.value.sources?.find((s) => s.id === sourceId)
  if (!source?.id) return

  sourceRenameHelpers.value[source.id] = {
    editMode: true,
    tempTitle: source.alias || '',
  }

  nextTick(() => {
    const input: HTMLInputElement | null = document.querySelector(`[data-source-rename-input-id="${sourceId}"]`)
    if (!input) return
    input?.focus()
    input?.select()
  })
}

const toggleSourceExpand = (sourceId: string) => {
  const key = `collapse-${sourceId}`
  const idx = activeKey.value.indexOf(key)
  if (idx >= 0) {
    activeKey.value.splice(idx, 1)
  } else {
    activeKey.value.push(key)
  }
}

const isSourceExpanded = (sourceId: string) => {
  return activeKey.value.includes(`collapse-${sourceId}`)
}

const showBaseOption = (source: SourceType) => {
  return ['airtableImport', 'csvImport', 'jsonImport', 'excelImport'].some((permission) => isUIAllowed(permission, { source }))
}

const updateSourceTitle = async (sourceId: string) => {
  const source = base.value.sources?.find((s) => s.id === sourceId)

  if (!source?.id || !sourceRenameHelpers.value[source.id]) return

  if (sourceRenameHelpers.value[source.id].tempTitle) {
    sourceRenameHelpers.value[source.id].tempTitle = sourceRenameHelpers.value[source.id].tempTitle.trim()
  }

  if (!sourceRenameHelpers.value[source.id].tempTitle) {
    delete sourceRenameHelpers.value[source.id]
    return
  }

  try {
    await api.source.update(source.base_id, source.id, {
      alias: sourceRenameHelpers.value[source.id].tempTitle,
    })

    await loadProject(source.base_id, true)

    delete sourceRenameHelpers.value[source.id]

    $e('a:source:rename')

    refreshViewTabTitle?.()
  } catch (e: any) {
    message.error(await extractSdkResponseErrorMsg(e))
  } finally {
    refreshCommandPalette()
  }
}

/**
 * Opens a dialog to create a new table.
 *
 * @returns {void}
 *
 * @remarks
 * This function is triggered when the user initiates the table creation process.
 * It opens a dialog for table creation, handles the dialog closure,
 * and potentially scrolls to the newly created table.
 *
 * @see {@link packages/nc-gui/components/smartsheet/topbar/TableListDropdown.vue} for a similar implementation
 * of table creation dialog. If this function is updated, consider updating the other implementation as well.
 */
function openTableCreateDialog(sourceIndex?: number | undefined, showSourceSelector = true) {
  const isOpen = ref(true)
  let sourceId = base.value!.sources?.[0].id
  if (typeof sourceIndex === 'number') {
    sourceId = base.value!.sources?.[sourceIndex].id
  }

  if (!sourceId || !base.value?.id) return

  const { close } = useDialog(resolveComponent('DlgTableCreate'), {
    'modelValue': isOpen,
    sourceId,
    'baseId': base.value!.id,
    'onCreate': closeDialog,
    'showSourceSelector': showSourceSelector,
    'onUpdate:modelValue': () => closeDialog(),
  })

  function closeDialog(table?: TableType) {
    isOpen.value = false

    if (!table) return

    isExpanded.value = true

    if (!activeKey.value || !activeKey.value.includes(`collapse-${sourceId}`)) {
      activeKey.value.push(`collapse-${sourceId}`)
    }

    // TODO: Better way to know when the table node dom is available
    setTimeout(() => {
      const newTableDom = document.querySelector(`[data-table-id="${table.id}"]`)
      if (!newTableDom) return

      newTableDom?.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
    }, 1000)

    close(1000)
  }
}

function openErdView(source: SourceType) {
  $e('c:project:relation')

  const isOpen = ref(true)

  const { close } = useDialog(resolveComponent('DlgBaseErd'), {
    'modelValue': isOpen,
    'sourceId': source!.id,
    'onUpdate:modelValue': () => closeDialog(),
    'baseId': base.value.id,
  })

  function closeDialog() {
    isOpen.value = false

    close(1000)
  }
}

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

    const sourceId = activeTable.value.source_id
    if (!sourceId) return

    if (!activeKey.value.includes(`collapse-${sourceId}`)) {
      activeKey.value.push(`collapse-${sourceId}`)
    }
  },
  {
    immediate: true,
  },
)

onKeyStroke('Escape', () => {
  for (const key of Object.keys(isBasesOptionsOpen.value)) {
    isBasesOptionsOpen.value[key] = false
  }
})
</script>

<template>
  <div class="nc-project-home-section">
    <div class="nc-project-home-section-header !cursor-pointer" @click.stop="isExpanded = !isExpanded">
      <div class="flex-1">{{ $t('objects.tables') }}</div>

      <GeneralIcon
        icon="chevronRight"
        class="flex-none nc-sidebar-source-node-btns cursor-pointer transform transition-transform duration-200 text-[20px] text-nc-content-gray-muted"
        :class="{ '!rotate-90': isExpanded }"
      />
    </div>
    <div key="g1" class="overflow-x-hidden transition-max-height" :class="{ 'max-h-0': !isExpanded }">
      <!-- Loading skeleton for initial load -->
      <DashboardTreeViewProjectListSkeletonEntity v-if="!baseTables.get(base?.id!)" class="!px-2.5 mt-2" />

      <template v-else-if="base && base?.sources">
        <div class="flex-1 overflow-y-auto overflow-x-hidden flex flex-col" :class="{ 'mb-[20px]': isSharedBase }">
          <div v-if="base?.sources?.[0]?.enabled" class="flex-1">
            <div class="transition-height duration-200">
              <DashboardTreeViewTableList :base="base" :base-id="baseId" :source-index="0" />
            </div>
          </div>

          <div v-if="base?.sources?.slice(1).some((el) => el.enabled)" class="transition-height duration-200">
            <div class="border-none sortable-list">
              <div v-for="(source, sourceIndex) of base.sources" :key="`source-${source.id}`">
                <template v-if="sourceIndex === 0"></template>
                <a-collapse
                  v-else-if="source && source.enabled"
                  v-model:active-key="activeKey"
                  v-e="['c:source:toggle-expand']"
                  class="!mx-0 !px-0 nc-sidebar-source-node nc-source-collapse-no-arrow"
                  :class="[{ hidden: searchActive && !!filterQuery }]"
                  :bordered="false"
                  ghost
                >
                  <template #expandIcon> </template>
                  <a-collapse-panel :key="`collapse-${source.id}`">
                    <template #header>
                      <div
                        :data-sourceId="source.id"
                        class="nc-sidebar-node min-w-20 w-full h-full flex flex-row group py-0.5 !mr-0"
                        :class="{
                          'pr-0.5': source.id && sourceRenameHelpers[source.id]?.editMode,
                        }"
                      >
                        <div
                          v-if="sourceIndex === 0"
                          class="source-context flex items-center gap-2 text-nc-content-gray nc-sidebar-node-title"
                          @contextmenu="setMenuContext('source', source)"
                        >
                          <div
                            class="hidden !xs:(flex items-center justify-center -mr-2) w-6 h-6 flex-none cursor-pointer"
                            @click.stop="toggleSourceExpand(source.id!)"
                          >
                            <GeneralIcon
                              icon="chevronRight"
                              class="transform transition-transform duration-200 !text-nc-content-gray-subtle2 text-[16px]"
                              :class="{ '!rotate-90': isSourceExpanded(source.id!) }"
                            />
                          </div>
                          <div class="flex items-center nc-source-icon-wrapper min-w-6 h-6 relative" @click.stop>
                            <NcButton
                              v-e="['c:source:toggle-expand']"
                              type="text"
                              size="xxsmall"
                              class="nc-source-chevron-btn !absolute inset-0 flex items-center justify-center opacity-0 z-10 text-nc-content-gray-subtle2 hover:text-nc-content-gray !rounded-md !xs:hidden"
                              @click.stop="toggleSourceExpand(source.id!)"
                            >
                              <GeneralIcon
                                icon="chevronRight"
                                class="cursor-pointer transform transition-transform duration-200 !text-current text-[16px]"
                                :class="{ '!rotate-90': isSourceExpanded(source.id!) }"
                              />
                            </NcButton>
                            <div class="flex items-center">
                              <GeneralBaseLogo class="flex-none min-w-4 !xs:(min-w-4.25 w-4.25 text-sm)" />
                            </div>
                          </div>
                          {{ $t('general.default') }}
                        </div>
                        <div
                          v-else
                          class="source-context flex flex-grow items-center gap-1 text-nc-content-gray min-w-1/20 max-w-full"
                          @contextmenu="setMenuContext('source', source)"
                        >
                          <div
                            class="hidden !xs:(flex items-center justify-center -mr-1) w-6 h-6 flex-none cursor-pointer"
                            @click.stop="toggleSourceExpand(source.id!)"
                          >
                            <GeneralIcon
                              icon="chevronRight"
                              class="transform transition-transform duration-200 !text-nc-content-gray-subtle2 text-[16px]"
                              :class="{ '!rotate-90': isSourceExpanded(source.id!) }"
                            />
                          </div>
                          <div class="flex items-center nc-source-icon-wrapper min-w-6 h-6 relative" @click.stop>
                            <NcButton
                              v-e="['c:source:toggle-expand']"
                              type="text"
                              size="xxsmall"
                              class="nc-source-chevron-btn !absolute inset-0 flex items-center justify-center opacity-0 z-10 text-nc-content-gray-subtle2 hover:text-nc-content-gray !rounded-md !xs:hidden"
                              @click.stop="toggleSourceExpand(source.id!)"
                            >
                              <GeneralIcon
                                icon="chevronRight"
                                class="cursor-pointer transform transition-transform duration-200 !text-current text-[16px]"
                                :class="{ '!rotate-90': isSourceExpanded(source.id!) }"
                              />
                            </NcButton>
                            <NcTooltip
                              :tooltip-style="{ 'min-width': 'max-content' }"
                              :overlay-inner-style="{ 'min-width': 'max-content' }"
                              :mouse-leave-delay="0.3"
                              placement="topLeft"
                              trigger="hover"
                              class="flex items-center"
                            >
                              <template #title>
                                <component :is="getSourceTooltip(source)" />
                              </template>
                              <div class="flex-none w-6 flex items-center justify-center">
                                <GeneralBaseLogo
                                  :color="getSourceIconColor(source)"
                                  class="flex-none min-w-4 !xs:(min-w-4.25 w-4.25 text-sm)"
                                />
                              </div>
                            </NcTooltip>
                          </div>
                          <a-input
                            v-if="source.id && sourceRenameHelpers[source.id]?.editMode"
                            ref="input"
                            v-model:value="sourceRenameHelpers[source.id].tempTitle"
                            class="capitalize !bg-transparent flex-1 mr-4 !pr-1.5 !text-nc-content-gray-subtle !rounded-md !h-6 animate-sidebar-node-input-padding"
                            :style="{
                              fontWeight: 'inherit',
                            }"
                            :data-source-rename-input-id="source.id"
                            @click.stop
                            @keydown.enter.stop.prevent
                            @keyup.enter="updateSourceTitle(source.id!)"
                            @keyup.esc="updateSourceTitle(source.id!)"
                            @blur="updateSourceTitle(source.id!)"
                            @keydown.stop
                          />
                          <NcTooltip
                            v-else
                            class="nc-sidebar-node-title capitalize text-ellipsis overflow-hidden select-none text-nc-content-gray-subtle"
                            :style="{ wordBreak: 'keep-all', whiteSpace: 'nowrap', display: 'inline' }"
                            show-on-truncate-only
                          >
                            <template #title> {{ source.alias || '' }}</template>
                            <span
                              :data-testid="`nc-sidebar-base-${source.alias}`"
                              @dblclick.stop="enableEditModeForSource(source.id!)"
                            >
                              {{ source.alias || '' }}
                            </span>
                          </NcTooltip>
                        </div>
                        <div
                          v-if="!(source.id && sourceRenameHelpers[source.id]?.editMode)"
                          class="flex flex-row items-center gap-x-0.25"
                        >
                          <NcDropdown
                            :visible="isBasesOptionsOpen[source!.id!]"
                            :trigger="['click']"
                            @update:visible="isBasesOptionsOpen[source!.id!] = $event"
                          >
                            <NcButton
                              v-e="['c:source:options']"
                              class="nc-sidebar-node-btn"
                              :class="{ '!text-nc-content-gray-extreme !opacity-100 !inline-block': isBasesOptionsOpen[source!.id!] }"
                              type="text"
                              size="xxsmall"
                              @click.stop="isBasesOptionsOpen[source!.id!] = !isBasesOptionsOpen[source!.id!]"
                            >
                              <GeneralIcon icon="threeDotHorizontal" class="text-xl w-4.75" />
                            </NcButton>
                            <template #overlay>
                              <NcMenu
                                class="nc-scrollbar-md !min-w-50"
                                :style="{
                                  maxHeight: '70vh',
                                  overflow: 'overlay',
                                }"
                                variant="small"
                                @click="isBasesOptionsOpen[source!.id!] = false"
                              >
                                <NcMenuItemCopyId
                                  :id="source.id"
                                  :tooltip="$t('labels.clickToCopySourceID')"
                                  :label="
                                    $t('labels.sourceIdColon', {
                                      sourceId: source.id,
                                    })
                                  "
                                  @click.stop
                                />
                                <NcDivider />

                                <NcMenuItem
                                  v-if="isUIAllowed('baseRename')"
                                  data-testid="nc-sidebar-source-rename"
                                  @click="enableEditModeForSource(source.id!)"
                                >
                                  <GeneralIcon icon="rename" />
                                  {{ $t('general.rename') }}
                                </NcMenuItem>

                                <NcDivider />

                                <!-- ERD View -->
                                <NcMenuItem key="erd" @click="openErdView(source)">
                                  <div v-e="['c:source:erd']" class="flex gap-2 items-center">
                                    <GeneralIcon icon="ncErd" />
                                    {{ $t('title.relations') }}
                                  </div>
                                </NcMenuItem>

                                <DashboardTreeViewBaseOptions
                                  v-if="showBaseOption(source)"
                                  v-model:base="base"
                                  :source="source"
                                  :show-source-selector="false"
                                />
                              </NcMenu>
                            </template>
                          </NcDropdown>

                          <NcButton
                            v-if="isUIAllowed('tableCreate', { roles: baseRole, source })"
                            v-e="['c:source:add-table']"
                            type="text"
                            size="xxsmall"
                            class="nc-sidebar-node-btn"
                            :class="{ '!opacity-100 !inline-block': isBasesOptionsOpen[source!.id!] }"
                            @click.stop="openTableCreateDialog(sourceIndex, false)"
                          >
                            <GeneralIcon icon="plus" class="text-xl leading-5" style="-webkit-text-stroke: 0.15px" />
                          </NcButton>
                        </div>
                      </div>
                    </template>
                    <div
                      ref="menuRefs"
                      :key="`sortable-${source.id}-${source.id && source.id in keys ? keys[source.id] : '0'}`"
                      :nc-source="source.id"
                    >
                      <DashboardTreeViewTableList :base="base" :base-id="baseId" :source-index="sourceIndex" />
                    </div>
                  </a-collapse-panel>
                </a-collapse>
              </div>
            </div>
          </div>
        </div>
      </template>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.nc-source-collapse-no-arrow {
  :deep(.ant-collapse-arrow) {
    @apply !hidden;
  }

  .nc-source-chevron-btn {
    @apply transition-opacity duration-150;
  }

  :deep(.nc-source-icon-wrapper > :not(.nc-source-chevron-btn)) {
    @apply transition-opacity duration-150;
  }

  @media (min-width: 481px) {
    :deep(.ant-collapse-header:hover) {
      .nc-source-chevron-btn {
        @apply !opacity-100;
      }

      .nc-source-icon-wrapper > :not(.nc-source-chevron-btn) {
        @apply !opacity-0;
      }
    }
  }
}
</style>
