<template>
  <LayoutDialog
    v-model:open="isOpen"
    max-width="sm"
    title="Create Token"
    :buttons="dialogButtons"
    prevent-close-on-click-outside
  >
    <form @submit="onSubmit">
      <div class="flex flex-col gap-6">
        <FormTextInput
          v-model="name"
          label="Name"
          help="A name to remember this token by. For example, the name of the script or application you're planning to use it in!"
          name="hookName"
          :rules="[isRequired]"
          show-required
          show-label
          type="text"
        />
        <FormSelectBadges
          v-model="scopes"
          multiple
          name="scopes"
          label="Scopes"
          placeholder="Choose Scopes"
          help="It's good practice to limit the scopes of your token to the absolute minimum. For example, if your application or script will only read and write streams, select just those scopes."
          show-required
          :rules="[isItemSelected]"
          show-label
          :items="apiTokenScopes"
          by="id"
        />
      </div>
    </form>
  </LayoutDialog>
</template>

<script setup lang="ts">
import { useMutation } from '@vue/apollo-composable'
import { AllScopes } from '@speckle/shared'
import { LayoutDialog, FormSelectBadges } from '@speckle/ui-components'
import { TokenFormValues } from '~~/lib/developer-settings/helpers/types'
import { createAccessTokenMutation } from '~~/lib/developer-settings/graphql/mutations'
import { isItemSelected, isRequired } from '~~/lib/common/helpers/validation'
import { useForm } from 'vee-validate'
import {
  convertThrowIntoFetchResult,
  getFirstErrorMessage
} from '~~/lib/common/helpers/graphql'
import { useGlobalToast, ToastNotificationType } from '~~/lib/common/composables/toast'

const emit = defineEmits<{
  (e: 'token-created', tokenId: string): void
}>()

const { mutate: createToken } = useMutation(createAccessTokenMutation)
const { triggerNotification } = useGlobalToast()
const { handleSubmit } = useForm<TokenFormValues>()

const isOpen = defineModel<boolean>('open', { required: true })

const name = ref('')
const scopes = ref<typeof apiTokenScopes.value>([])

const apiTokenScopes = computed(() => {
  return Object.values(AllScopes).map((value) => ({
    id: value,
    text: value
  }))
})

const onSubmit = handleSubmit(async (tokenFormValues) => {
  const result = await createToken({
    token: {
      name: name.value,
      scopes: tokenFormValues.scopes.map((t) => t.id)
    }
  }).catch(convertThrowIntoFetchResult)

  if (result?.data?.apiTokenCreate) {
    isOpen.value = false
    resetFormFields()
    emit('token-created', result.data.apiTokenCreate)
    triggerNotification({
      type: ToastNotificationType.Success,
      title: 'Webhook created',
      description: 'The webhook has been successfully created'
    })
  } else {
    const errorMessage = getFirstErrorMessage(result?.errors)
    triggerNotification({
      type: ToastNotificationType.Danger,
      title: 'Failed to create token',
      description: errorMessage
    })
  }
})

const dialogButtons = computed(() => [
  {
    text: 'Cancel',
    props: { color: 'secondary', fullWidth: true, outline: true },
    onClick: () => {
      isOpen.value = false
    }
  },
  {
    text: 'Create',
    props: { color: 'primary', fullWidth: true },
    onClick: onSubmit
  }
])

const resetFormFields = () => {
  name.value = ''
  scopes.value = []
}

watch(
  () => isOpen.value,
  (newVal) => {
    if (newVal) {
      resetFormFields()
    }
  }
)
</script>
