<template>
  <div class="w-64 mt-2">
    <span class="pl-3 text-muted text-md font-semibold opacity-70">
      {{ $t('manager.selectVersion') }}
    </span>
    <div
      v-if="isLoadingVersions || isQueueing"
      class="text-center text-muted py-4 flex flex-col items-center"
    >
      <ProgressSpinner class="w-8 h-8 mb-2" />
      {{ $t('manager.loadingVersions') }}
    </div>
    <div v-else-if="versionOptions.length === 0" class="py-2">
      <NoResultsPlaceholder
        :title="$t('g.noResultsFound')"
        :message="$t('manager.tryAgainLater')"
        icon="pi pi-exclamation-circle"
        class="p-0"
      />
    </div>
    <Listbox
      v-else
      v-model="selectedVersion"
      option-label="label"
      option-value="value"
      :options="versionOptions"
      :highlight-on-select="false"
      class="my-3 w-full max-h-[50vh] border-none shadow-none"
    >
      <template #option="slotProps">
        <div class="flex justify-between items-center w-full p-1">
          <span>{{ slotProps.option.label }}</span>
          <i
            v-if="selectedVersion === slotProps.option.value"
            class="pi pi-check text-highlight"
          />
        </div>
      </template>
    </Listbox>
    <ContentDivider class="my-2" />
    <div class="flex justify-end gap-2 p-1 px-3">
      <Button
        text
        severity="secondary"
        :label="$t('g.cancel')"
        :disabled="isQueueing"
        @click="emit('cancel')"
      />
      <Button
        severity="secondary"
        :label="$t('g.install')"
        class="py-3 px-4 dark-theme:bg-unset bg-black/80 dark-theme:text-unset text-neutral-100 rounded-lg"
        :disabled="isQueueing"
        @click="handleSubmit"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { whenever } from '@vueuse/core'
import Button from 'primevue/button'
import Listbox from 'primevue/listbox'
import ProgressSpinner from 'primevue/progressspinner'
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'

import ContentDivider from '@/components/common/ContentDivider.vue'
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
import { useComfyRegistryService } from '@/services/comfyRegistryService'
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import type { components } from '@/types/comfyRegistryTypes'
import { components as ManagerComponents } from '@/types/generatedManagerTypes'
import { isSemVer } from '@/utils/formatUtil'

const { nodePack } = defineProps<{
  nodePack: components['schemas']['Node']
}>()

const emit = defineEmits<{
  cancel: []
  submit: []
}>()

const { t } = useI18n()
const registryService = useComfyRegistryService()
const managerStore = useComfyManagerStore()

const isQueueing = ref(false)

const selectedVersion = ref<string>('latest')
onMounted(() => {
  const initialVersion = getInitialSelectedVersion() ?? 'latest'
  selectedVersion.value =
    // Use NIGHTLY when version is a Git hash
    isSemVer(initialVersion) ? initialVersion : 'nightly'
})

const getInitialSelectedVersion = () => {
  if (!nodePack.id) return

  // If unclaimed, set selected version to nightly
  if (nodePack.publisher?.name === 'Unclaimed')
    return 'nightly' as ManagerComponents['schemas']['SelectedVersion']

  // If node pack is installed, set selected version to the installed version
  if (managerStore.isPackInstalled(nodePack.id))
    return managerStore.getInstalledPackVersion(nodePack.id)

  // If node pack is not installed, set selected version to latest
  return nodePack.latest_version?.version
}

const fetchVersions = async () => {
  if (!nodePack?.id) return []
  return (await registryService.getPackVersions(nodePack.id)) || []
}

const versionOptions = ref<
  {
    value: string
    label: string
  }[]
>([])

const isLoadingVersions = ref(false)

const onNodePackChange = async () => {
  isLoadingVersions.value = true

  // Fetch versions from the registry
  const versions = await fetchVersions()
  const availableVersionOptions = versions
    .map((version) => ({
      value: version.version ?? '',
      label: version.version ?? ''
    }))
    .filter((option) => option.value)

  // Add Latest option
  const defaultVersions = [
    {
      value: 'latest' as ManagerComponents['schemas']['SelectedVersion'],
      label: t('manager.latestVersion')
    }
  ]

  // Add Nightly option if there is a non-empty `repository` field
  if (nodePack.repository?.length) {
    defaultVersions.push({
      value: 'nightly' as ManagerComponents['schemas']['SelectedVersion'],
      label: t('manager.nightlyVersion')
    })
  }

  versionOptions.value = [...defaultVersions, ...availableVersionOptions]
  isLoadingVersions.value = false
}

whenever(
  () => nodePack.id,
  (nodePackId, oldNodePackId) => {
    if (nodePackId !== oldNodePackId) {
      void onNodePackChange()
    }
  },
  { deep: true, immediate: true }
)

const handleSubmit = async () => {
  isQueueing.value = true
  if (!nodePack.id) {
    throw new Error('Node ID is required for installation')
  }

  await managerStore.installPack.call({
    id: nodePack.id,
    version: selectedVersion.value,
    repository: nodePack.repository ?? '',
    channel: 'default' as ManagerComponents['schemas']['ManagerChannel'],
    mode: 'cache' as ManagerComponents['schemas']['ManagerDatabaseSource'],
    selected_version: selectedVersion.value
  })

  isQueueing.value = false
  emit('submit')
}
</script>
