<script setup lang="ts">
interface Prop {
  extensionId: string
  error?: any
}

const { extensionId, error } = defineProps<Prop>()

const {
  extensionList,
  extensionsLoaded,
  availableExtensions,
  eventBus,
  getExtensionAssetsUrl,
  duplicateExtension,
  showExtensionDetails,
} = useExtensions()

const activeError = ref(error)

const extensionRef = ref<HTMLElement>()

const extensionModalRef = ref<HTMLElement>()

const isMouseDown = ref(false)

const extension = computed(() => {
  const ext = extensionList.value.find((ext) => ext.id === extensionId)
  if (!ext) {
    throw new Error('Extension not found')
  }
  return ext
})

const titleInput = ref<HTMLInputElement | null>(null)

const titleEditMode = ref<boolean>(false)

const tempTitle = ref<string>(extension.value.title)

const enableEditMode = () => {
  titleEditMode.value = true
  tempTitle.value = extension.value.title
  nextTick(() => {
    titleInput.value?.focus()
    titleInput.value?.select()
  })
}

const updateExtensionTitle = async () => {
  await extension.value.setTitle(tempTitle.value)
  titleEditMode.value = false
}

const { fullscreen, collapsed } = useProvideExtensionHelper(extension)

const component = ref<any>(null)

const extensionManifest = ref<ExtensionManifest | undefined>()

const fullscreenModalMaxWidth = computed(() => {
  const modalMaxWidth = {
    xs: 'min(calc(100vw - 32px), 448px)',
    sm: 'min(calc(100vw - 32px), 640px)',
    md: 'min(calc(100vw - 48px), 900px)',
    lg: 'min(calc(100vw - 48px), 1280px)',
  }

  return extensionManifest.value?.config?.modalMaxWith
    ? modalMaxWidth[extensionManifest.value?.config?.modalMaxWith] || modalMaxWidth.lg
    : modalMaxWidth.lg
})

const expandExtension = () => {
  if (!collapsed.value) return

  collapsed.value = false
}

onMounted(() => {
  until(extensionsLoaded)
    .toMatch((v) => v)
    .then(() => {
      extensionManifest.value = availableExtensions.value.find((ext) => ext.id === extension.value.extensionId)

      if (!extensionManifest.value) {
        return
      }

      import(`../../extensions/${extensionManifest.value.entry}/index.vue`).then((mod) => {
        component.value = markRaw(mod.default)
      })
    })
    .catch((err) => {
      if (!extensionManifest.value) {
        activeError.value = 'There was an error loading the extension'
        return
      }
      activeError.value = err
    })
})

// close fullscreen on escape key press
useEventListener('keydown', (e) => {
  // Check if the event target or its closest parent is an input, select, or textarea
  const isFormElement = (e?.target as HTMLElement)?.closest('input, select, textarea')

  // If the target is not a form element and the key is 'Escape', close fullscreen
  if (e.key === 'Escape' && !isFormElement) {
    fullscreen.value = false
  }
})

// close fullscreen on clicking extensionModalRef directly
const closeFullscreen = (e: MouseEvent) => {
  if (e.target === extensionModalRef.value) {
    fullscreen.value = false
  }
}

const handleDuplicateExtension = async (id: string, open: boolean = false) => {
  const duplicatedExt = await duplicateExtension(id)

  if (duplicatedExt?.id && open) {
    fullscreen.value = false
    eventBus.emit(ExtensionsEvents.DUPLICATE, duplicatedExt.id)
  }
}

// #Listeners
eventBus.on((event, payload) => {
  if (event === ExtensionsEvents.DUPLICATE && extension.value.id === payload) {
    setTimeout(() => {
      nextTick(() => {
        extensionRef.value?.scrollIntoView({ behavior: 'smooth', block: 'start' })
      })
    }, 500)
  }
})
</script>

<template>
  <div ref="extensionRef" class="w-full px-4" :data-testid="extension.id">
    <div
      class="extension-wrapper"
      :class="[
        {
          '!h-auto': collapsed,
          'isOpen': !collapsed,
          'mousedown': isMouseDown,
        },
      ]"
      :style="
        !collapsed
          ? {
              height: extensionManifest?.config?.contentMinHeight,
              minHeight: extensionManifest?.config?.contentMinHeight,
            }
          : {}
      "
      @mousedown="isMouseDown = true"
      @mouseup="isMouseDown = false"
    >
      <div
        class="extension-header px-3 py-2"
        :class="{
          'border-b-1 border-gray-200 h-[49px]': !collapsed,
          'collapsed border-transparent h-[48px]': collapsed,
        }"
        @click="expandExtension"
      >
        <div class="extension-header-left max-w-[calc(100%_-_100px)]">
          <!-- Todo: enable later when we support extension reordering -->
          <!-- eslint-disable vue/no-constant-condition -->
          <NcButton size="xs" type="text" class="nc-extension-drag-handler !px-1" @click.stop>
            <GeneralIcon icon="ncDrag" class="flex-none text-gray-500" />
          </NcButton>

          <img
            v-if="extensionManifest"
            :src="getExtensionAssetsUrl(extensionManifest.iconUrl)"
            alt="icon"
            class="h-8 w-8 object-contain"
          />
          <a-input
            v-if="titleEditMode && !fullscreen"
            ref="titleInput"
            v-model:value="tempTitle"
            type="text"
            class="flex-grow !h-8 !px-1 !py-1 !-ml-1 !rounded-lg w-4/5 extension-title"
            @click.stop
            @keyup.enter="updateExtensionTitle"
            @keyup.esc="updateExtensionTitle"
            @blur="updateExtensionTitle"
          >
          </a-input>

          <NcTooltip v-else show-on-truncate-only class="truncate">
            <template #title>
              {{ extension.title }}
            </template>
            <span class="extension-title cursor-pointer" @dblclick.stop="enableEditMode" @click.stop>
              {{ extension.title }}
            </span>
          </NcTooltip>
        </div>
        <div class="extension-header-right" @click.stop>
          <ExtensionsExtensionMenu
            :active-error="activeError"
            class="nc-extension-menu"
            @rename="enableEditMode"
            @duplicate="handleDuplicateExtension(extension.id, true)"
            @show-details="showExtensionDetails(extension.extensionId, 'extension')"
            @clear-data="extension.clear()"
            @delete="extension.delete()"
          />
          <NcButton v-if="!activeError" type="text" size="xs" class="nc-extension-expand-btn !px-1" @click="fullscreen = true">
            <GeneralIcon icon="ncMaximize2" class="h-3.5 w-3.5" />
          </NcButton>
          <NcButton size="xs" type="text" class="!px-1" @click="collapsed = !collapsed">
            <GeneralIcon :icon="collapsed ? 'arrowDown' : 'arrowUp'" class="flex-none" />
          </NcButton>
        </div>
      </div>

      <template v-if="activeError">
        <div
          v-show="!collapsed"
          class="extension-content nc-scrollbar-thin h-[calc(100%_-_50px)] flex items-center justify-center"
          :class="{
            fullscreen,
          }"
        >
          <a-result status="error" title="Extension Error" class="nc-extension-error">
            <template #subTitle>{{ activeError }}</template>
            <template #extra>
              <NcButton size="small" @click="extension.clear()">
                <div class="flex items-center gap-2">
                  <GeneralIcon icon="reload" />
                  Clear Data
                </div>
              </NcButton>
              <NcButton size="small" type="danger" @click="extension.delete()">
                <div class="flex items-center gap-2">
                  <GeneralIcon icon="delete" />
                  Delete
                </div>
              </NcButton>
            </template>
          </a-result>
        </div>
      </template>
      <template v-else>
        <Teleport to="body" :disabled="!fullscreen">
          <div
            ref="extensionModalRef"
            :class="{ 'extension-modal': fullscreen, 'h-[calc(100%_-_50px)]': !fullscreen }"
            @click="closeFullscreen"
          >
            <div
              :class="{ 'extension-modal-content': fullscreen, 'h-full': !fullscreen }"
              :style="
                fullscreen
                  ? {
                      maxWidth: fullscreenModalMaxWidth,
                    }
                  : {}
              "
            >
              <div v-if="fullscreen" class="flex items-center justify-between cursor-default">
                <div class="flex-1 max-w-[calc(100%_-_96px)] flex items-center gap-2 text-gray-800 font-semibold">
                  <img
                    v-if="extensionManifest"
                    :src="getExtensionAssetsUrl(extensionManifest.iconUrl)"
                    alt="icon"
                    class="flex-none w-8 h-8"
                  />

                  <a-input
                    v-if="titleEditMode"
                    ref="titleInput"
                    v-model:value="tempTitle"
                    type="text"
                    class="flex-grow !h-8 !px-1 !py-1 !-ml-1 !rounded-lg !text-lg font-semibold extension-title max-w-[420px]"
                    @click.stop
                    @keyup.enter.stop="updateExtensionTitle"
                    @keyup.esc.stop="updateExtensionTitle"
                    @blur="updateExtensionTitle"
                  >
                  </a-input>
                  <NcTooltip v-else show-on-truncate-only class="extension-title truncate text-lg">
                    <template #title>
                      {{ extension.title }}
                    </template>
                    <span class="cursor-pointer" @dblclick="enableEditMode">
                      {{ extension.title }}
                    </span>
                  </NcTooltip>
                </div>
                <div class="flex items-center gap-4">
                  <ExtensionsExtensionMenu
                    :active-error="activeError"
                    :fullscreen="fullscreen"
                    @rename="enableEditMode"
                    @duplicate="handleDuplicateExtension(extension.id, true)"
                    @show-details="showExtensionDetails(extension.extensionId, 'extension')"
                    @clear-data="extension.clear()"
                    @delete="extension.delete()"
                  />
                  <NcButton size="small" type="text" class="flex-none" @click="fullscreen = false">
                    <GeneralIcon icon="close" />
                  </NcButton>
                </div>
              </div>
              <div
                v-show="fullscreen || !collapsed"
                class="extension-content"
                :class="{ 'fullscreen h-[calc(100%-40px)]': fullscreen, 'h-full': !fullscreen }"
              >
                <component :is="component" :key="extension.uiKey" class="h-full" />
              </div>
            </div>
          </div>
        </Teleport>
      </template>
    </div>
  </div>
</template>

<style scoped lang="scss">
.extension-wrapper {
  @apply bg-white rounded-xl w-full border-1 relative;

  &.isOpen {
    resize: vertical;

    &:hover,
    &.mousedown {
      overflow-y: auto;
    }
  }
}

.extension-header {
  @apply flex justify-between;

  &.collapsed:not(:hover) {
    .nc-extension-expand-btn,
    .nc-extension-menu {
      @apply hidden;
    }
  }

  .extension-header-left {
    @apply flex-1 flex items-center gap-2;
  }

  .extension-header-right {
    @apply flex items-center gap-1;
  }

  .extension-title {
    @apply font-weight-600;
  }
}

.extension-content {
  @apply rounded-lg;

  &:not(.fullscreen) {
    @apply p-3;
  }
}

.extension-modal {
  @apply absolute top-0 left-0 z-1000 w-full h-full bg-black bg-opacity-50;

  .extension-modal-content {
    @apply bg-white rounded-2xl w-[90%] h-[90vh] mt-[5vh] mx-auto p-6 flex flex-col gap-3;
  }
}

:deep(.nc-extension-error.ant-result) {
  @apply p-0;
  .ant-result-icon {
    @apply mb-3;
    & > span {
      @apply text-[32px];
    }
  }

  .ant-result-title {
    @apply text-base text-gray-800 font-semibold;
  }

  .ant-result-extra {
    @apply mt-3;
  }
}
</style>
