<script setup lang="ts">
import { PlanFeatureTypes, PlanTitles } from 'nocodb-sdk'
import {
  type BaseType,
  type LinkToAnotherRecordType,
  ProjectRoles,
  type TableType,
  UITypes,
  type WorkspaceType,
  WorkspaceUserRoles,
} from 'nocodb-sdk'

const props = defineProps<{
  modelValue: boolean
  table: TableType
}>()

const emit = defineEmits(['update:modelValue'])

const { api } = useApi()

const dialogShow = useVModel(props, 'modelValue', emit)

const { $e, $poller } = useNuxtApp()

const basesStore = useBases()

const { createProject: _createProject, loadProjects } = basesStore

const { openTable, loadProjectTables } = useTablesStore()

const baseStore = useBase()

const { loadTables } = baseStore

const { base: activeBase } = storeToRefs(baseStore)

const { tables } = storeToRefs(baseStore)

const { getMeta } = useMetas()

const { t } = useI18n()

const { activeTable: _activeTable } = storeToRefs(useTablesStore())

const { refreshCommandPalette } = useCommandPalette()

const { workspacesList, activeWorkspace } = useWorkspace()

const { appInfo } = useGlobal()

const { getFeature } = useEeConfig()

const isEeActive = computed(() => isEeUI && appInfo.value?.ee)

// #region target base
const wsDropdownOpen = ref(false)
const baseDropdownOpen = ref(false)
const targetWorkspace = ref(activeWorkspace)
const targetBase = ref(activeBase.value)

const targetTableMeta = computedAsync(async () => {
  return getMeta(activeBase.value?.id, props.table.id!)
})

const canTargetOtherBase = computed(() => {
  if (!targetTableMeta.value || (targetTableMeta.value.columns?.length ?? 0) === 0) return false
  return (
    isEeActive.value &&
    !targetTableMeta.value.columns?.some((col) => [UITypes.Links, UITypes.LinkToAnotherRecord].includes(col.uidt!))
  )
})

const isTargetOtherWsSufficientPlan = computed(() => {
  return getFeature(PlanFeatureTypes.FEATURE_DUPLICATE_TABLE_TO_OTHER_WS)
})

const workspaceOptions = computed(() => {
  if (!isEeActive.value || !activeWorkspace) return []
  if (!isTargetOtherWsSufficientPlan.value) return [activeWorkspace]

  return workspacesList.filter((ws) =>
    [WorkspaceUserRoles.CREATOR, WorkspaceUserRoles.OWNER].includes(ws.roles as WorkspaceUserRoles),
  )
})

const isTargetOtherBaseSufficientPlan = computed(() => {
  return getFeature(PlanFeatureTypes.FEATURE_DUPLICATE_TABLE_TO_OTHER_BASE)
})

const targetBases: Ref<BaseType[]> = ref([])

const refreshTargetBases = async () => {
  if (!isEeActive.value || !targetWorkspace.value) {
    targetBases.value = []
    return
  }
  if (!isTargetOtherBaseSufficientPlan.value) {
    targetBases.value = [activeBase.value]
    return
  }
  const bases = await loadProjects(undefined, targetWorkspace.value.id)
  targetBases.value.splice(0)
  targetBases.value.push(
    ...((bases as any[])?.filter(
      (base) =>
        [WorkspaceUserRoles.CREATOR, WorkspaceUserRoles.OWNER].includes(targetWorkspace.value!.roles as WorkspaceUserRoles) ||
        [ProjectRoles.OWNER, ProjectRoles.CREATOR].includes(base.project_role),
    ) ?? []),
  )
}

const selectWorkspace = async (option: WorkspaceType) => {
  if (option.id !== targetWorkspace.value?.id) {
    targetBase.value = null as any
  }
  targetWorkspace.value = option
  wsDropdownOpen.value = false
  await refreshTargetBases()
  targetBase.value = targetBases.value?.[0] as any
}

const selectBase = (option: BaseType) => {
  targetBase.value = option
  baseDropdownOpen.value = false
}
// #endregion taget base

const options = ref({
  includeData: true,
  includeViews: true,
  includeHooks: true,
})

const optionsToExclude = computed(() => {
  const { includeData, includeViews, includeHooks } = options.value
  return {
    excludeData: !includeData,
    excludeViews: !includeViews,
    excludeHooks: !includeHooks,
  }
})

const isLoading = ref(false)

const _duplicate = async () => {
  try {
    isLoading.value = true
    const isContextDifferent = targetBase.value && targetBase.value.id !== activeBase.value.id
    const jobData = await api.dbTable.duplicate(props.table.base_id!, props.table.id!, {
      options: {
        ...optionsToExclude.value,
        ...(isContextDifferent ? { targetWorkspaceId: targetWorkspace.value!.id, targetBaseId: targetBase.value.id } : {}),
      },
    })

    $poller.subscribe(
      { id: jobData.id },
      async (data: {
        id: string
        status?: string
        data?: {
          error?: {
            message: string
          }
          message?: string
          result?: any
        }
      }) => {
        if (data.status !== 'close') {
          if (data.status === JobStatus.COMPLETED) {
            try {
              const sourceTable = await getMeta(activeBase.value?.id, props.table.id!)
              if (sourceTable) {
                for (const col of sourceTable.columns || []) {
                  if ([UITypes.Links, UITypes.LinkToAnotherRecord].includes(col.uidt as UITypes)) {
                    if (col && col.colOptions) {
                      const relatedTableId = (col.colOptions as LinkToAnotherRecordType)?.fk_related_model_id
                      const relatedBaseId = (col.colOptions as any)?.fk_related_base_id || activeBase.value?.id
                      if (relatedTableId && relatedBaseId) {
                        await getMeta(relatedBaseId, relatedTableId, true)
                      }
                    }
                  }
                }
              }

              if (!isContextDifferent) {
                await loadTables()
                refreshCommandPalette()
                const newTable = tables.value.find((el) => el.id === data?.data?.result?.id)

                openTable(newTable!)
              } else {
                // Load target base tables if target workspace is the same as active workspace
                if (targetWorkspace.value?.id === activeWorkspace?.id) {
                  await loadProjectTables(targetBase.value.id!, true)
                  refreshCommandPalette()
                }

                // TODO: navigating to specified base?
                message.success(t(`msg.success.tableDuplicatedInOtherBase`))
              }
            } catch (_e: any) {
              // ignore
            }
            isLoading.value = false
            dialogShow.value = false
          } else if (data.status === JobStatus.FAILED) {
            message.error(t('msg.error.failedToDuplicateTable'))

            try {
              await loadTables()
            } catch (_e: any) {
              // ignore
            }

            isLoading.value = false
            dialogShow.value = false
          }
        }
      },
    )

    $e('a:table:duplicate')
  } catch (e: any) {
    message.error(await extractSdkResponseErrorMsg(e))
    isLoading.value = false
    dialogShow.value = false
  }
}

onKeyStroke('Enter', () => {
  // should only trigger this when our modal is open
  if (dialogShow.value) {
    _duplicate()
  }
})

watch(isTargetOtherBaseSufficientPlan, (newValue) => {
  if (newValue) {
    refreshTargetBases()
  }
})

const isEaster = ref(false)

onMounted(() => {
  refreshTargetBases()
})
</script>

<template>
  <GeneralModal
    v-model:visible="dialogShow"
    :class="{ active: dialogShow }"
    :mask-closable="!isLoading"
    :keyboard="!isLoading"
    centered
    wrap-class-name="nc-modal-table-duplicate"
    :mask-style="{
      'background-color': 'rgba(0, 0, 0, 0.08)',
    }"
    :footer="null"
    class="!w-[30rem]"
    @keydown.esc="dialogShow = false"
  >
    <div>
      <div class="text-base text-nc-content-gray-emphasis leading-6 font-bold self-center" @dblclick="isEaster = !isEaster">
        {{ $t('general.duplicate') }} {{ $t('objects.table') }} "{{ table.title }}"
      </div>

      <div class="mt-5 flex gap-3 flex-col">
        <div class="flex">
          <div
            class="flex gap-3 cursor-pointer leading-5 text-nc-content-gray font-medium items-center"
            @click="options.includeData = !options.includeData"
          >
            <NcSwitch :checked="options.includeData" />
            {{ $t('labels.includeRecords') }}
          </div>
        </div>
        <div class="flex">
          <div
            class="flex gap-3 cursor-pointer leading-5 text-nc-content-gray font-medium items-center"
            @click="options.includeViews = !options.includeViews"
          >
            <NcSwitch :checked="options.includeViews" />
            {{ $t('labels.includeView') }}
          </div>
        </div>

        <div v-show="isEaster" class="flex">
          <div
            class="flex gap-3 cursor-pointer leading-5 text-nc-content-gray font-medium items-center"
            @click="options.includeHooks = !options.includeHooks"
          >
            <NcSwitch :checked="options.includeHooks" />
            {{ $t('labels.includeWebhook') }}
          </div>
        </div>
      </div>

      <div v-if="isEeActive" class="mb-5">
        <NcDivider divider-class="!my-5" />

        <div v-if="isTargetOtherWsSufficientPlan" class="text-nc-content-gray font-medium leading-5 mb-2">
          {{ $t('labels.workspace') }}
          <div class="flex items-center content-center gap-2">
            <NcTooltip :disabled="canTargetOtherBase" class="mt-2 flex-1">
              <template v-if="!canTargetOtherBase" #title>
                <span> This table contains linked records that reference data in the current base. </span>
              </template>
              <NcListDropdown v-model:is-open="wsDropdownOpen" :disabled="!canTargetOtherBase" default-slot-wrapper-class="gap-2">
                <GeneralWorkspaceIcon size="small" :workspace="targetWorkspace!" />

                <div class="flex-1 capitalize truncate">
                  {{ targetWorkspace?.title }}
                </div>

                <div class="flex gap-2 items-center">
                  <div v-if="activeWorkspace?.id === targetWorkspace?.id" class="text-nc-content-gray-muted leading-4.5 text-xs">
                    {{ $t('labels.currentWorkspace') }}
                  </div>
                  <GeneralIcon
                    :class="{
                      'transform rotate-180': wsDropdownOpen,
                    }"
                    class="transition-all w-4 h-4 opacity-80"
                    icon="ncChevronDown"
                  />
                </div>

                <template #overlay="{ onEsc }">
                  <NcList
                    v-model:open="wsDropdownOpen"
                    :value="targetWorkspace?.id ?? ''"
                    :item-height="32"
                    close-on-select
                    class="nc-base-workspace-selection w-full"
                    :min-items-for-search="6"
                    container-class-name="w-full"
                    :list="workspaceOptions"
                    option-label-key="title"
                    option-value-key="id"
                    stop-propagation-on-item-click
                    @change="(option) => selectWorkspace(option as WorkspaceType)"
                    @escape="onEsc"
                  >
                    <template #listHeader>
                      <div class="text-nc-content-gray-muted text-[13px] px-3 pt-2.5 pb-1.5 font-medium leading-5">
                        {{ $t('labels.duplicateTableMessage') }}
                      </div>

                      <NcDivider />
                    </template>

                    <template #listItemExtraLeft="{ option: optionItem }">
                      <GeneralWorkspaceIcon :workspace="optionItem as WorkspaceType" size="small" />
                    </template>
                    <template #listItemExtraRight="{ option: optionItem }">
                      <div v-if="activeWorkspace?.id === optionItem.id" class="text-nc-content-gray-muted leading-4.5 text-xs">
                        {{ $t('labels.currentWorkspace') }}
                      </div>
                    </template>
                  </NcList>
                </template>
              </NcListDropdown>
            </NcTooltip>
            <LazyPaymentUpgradeBadge
              class="mt-2"
              :feature="PlanFeatureTypes.FEATURE_DUPLICATE_TABLE_TO_OTHER_WS"
              :plan-title="PlanTitles.ENTERPRISE"
              :content="$t('upgrade.upgradeToDuplicateTableToOtherWs')"
              :on-click-callback="
                () => {
                  dialogShow = false
                }
              "
            />
          </div>
        </div>

        <div class="text-nc-content-gray font-medium leading-5">
          {{ $t('objects.project') }}

          <div class="flex items-center content-center gap-2">
            <NcTooltip :disabled="canTargetOtherBase && isTargetOtherBaseSufficientPlan" class="mt-2 flex-1">
              <template v-if="!canTargetOtherBase || !isTargetOtherBaseSufficientPlan" #title>
                <span v-if="!canTargetOtherBase">
                  This table contains linked records that reference data in the current base.
                </span>
                <span v-if="!isTargetOtherBaseSufficientPlan">
                  {{ $t('upgrade.upgradeToDuplicateTableToOtherBase') }}
                </span>
              </template>
              <NcListDropdown
                v-model:is-open="baseDropdownOpen"
                :disabled="!canTargetOtherBase || !isTargetOtherBaseSufficientPlan"
                default-slot-wrapper-class="gap-2"
              >
                <template v-if="!!targetBase">
                  <div class="flex-1 capitalize truncate flex gap-1">
                    <GeneralProjectIcon
                      :color="parseProp(targetBase?.meta ?? {}).iconColor"
                      :managed-app="{
                        managed_app_master: targetBase?.managed_app_master,
                        managed_app_id: targetBase?.managed_app_id,
                      }"
                      size="small"
                    />
                    {{ targetBase?.title }}
                  </div>
                </template>
                <template v-else>
                  <div class="flex-1 capitalize truncate flex gap-1"></div>
                </template>
                <div class="flex gap-2 items-center">
                  <div v-if="activeBase?.id === targetBase?.id" class="text-nc-content-gray-muted leading-4.5 text-xs">
                    {{ $t('labels.currentBase') }}
                  </div>
                  <GeneralIcon
                    :class="{
                      'transform rotate-180': baseDropdownOpen,
                    }"
                    class="transition-all w-4 h-4 opacity-80"
                    icon="ncChevronDown"
                  />
                </div>

                <template #overlay="{ onEsc }">
                  <NcList
                    v-model:open="baseDropdownOpen"
                    :value="targetBase?.id ?? ''"
                    :item-height="32"
                    close-on-select
                    class="nc-base-workspace-selection"
                    :min-items-for-search="6"
                    container-class-name="w-full"
                    :list="targetBases"
                    option-label-key="title"
                    option-value-key="id"
                    stop-propagation-on-item-click
                    @change="(option) => selectBase(option as BaseType)"
                    @escape="onEsc"
                  >
                    <template #listHeader>
                      <div class="text-nc-content-gray-muted text-[13px] px-3 pt-2.5 pb-1.5 font-medium leading-5">
                        {{ $t('labels.duplicateTableMessage') }}
                      </div>

                      <NcDivider />
                    </template>

                    <template #listItemExtraLeft="{ option: optionItem }">
                      <GeneralProjectIcon
                        :color="parseProp(optionItem.meta).iconColor"
                        :managed-app="{
                          managed_app_master: optionItem.managed_app_master,
                          managed_app_id: optionItem.managed_app_id,
                        }"
                        size="small"
                      />
                    </template>
                    <template #listItemExtraRight="{ option: optionItem }">
                      <div v-if="activeBase?.id === optionItem.id" class="text-nc-content-gray-muted leading-4.5 text-xs">
                        {{ $t('labels.currentBase') }}
                      </div>
                    </template>
                  </NcList>
                </template>
              </NcListDropdown>
            </NcTooltip>
            <LazyPaymentUpgradeBadge
              class="mt-2"
              :feature="PlanFeatureTypes.FEATURE_DUPLICATE_TABLE_TO_OTHER_BASE"
              :content="$t('upgrade.upgradeToDuplicateTableToOtherBase')"
              :on-click-callback="
                () => {
                  dialogShow = false
                }
              "
            />
          </div>
        </div>
      </div>
    </div>
    <div class="flex flex-row gap-x-2 mt-5 justify-end">
      <NcButton v-if="!isLoading" key="back" type="secondary" size="small" @click="dialogShow = false">{{
        $t('general.cancel')
      }}</NcButton>
      <NcButton key="submit" v-e="['a:table:duplicate']" type="primary" size="small" :loading="isLoading" @click="_duplicate">
        Duplicate Table
      </NcButton>
    </div>
  </GeneralModal>
</template>

<style scoped lang="scss">
.nc-list-root {
  @apply !w-[432px] !pt-0;
}
</style>

<style lang="scss">
.nc-base-workspace-selection {
  .nc-list {
    @apply !px-1;
    .nc-list-item {
      @apply !py-1;
    }
  }
}
</style>
