<script setup lang="ts">
import type { ComponentPublicInstance } from '@vue/runtime-core'
import type { Form as AntForm, SelectProps } from 'ant-design-vue'
import { capitalize } from '@vue/runtime-core'
import type { FormType, GalleryType, GridType, KanbanType } from 'nocodb-sdk'
import { UITypes, ViewTypes } from 'nocodb-sdk'
import {
  MetaInj,
  ViewListInj,
  computed,
  generateUniqueTitle,
  inject,
  message,
  nextTick,
  reactive,
  unref,
  useApi,
  useI18n,
  useVModel,
  watch,
} from '#imports'

interface Props {
  modelValue: boolean
  type: ViewTypes
  title?: string
  selectedViewId?: string
  groupingFieldColumnId?: string
}

interface Emits {
  (event: 'update:modelValue', value: boolean): void
  (event: 'created', value: GridType | KanbanType | GalleryType | FormType): void
}

interface Form {
  title: string
  type: ViewTypes
  copy_from_id: string | null
  // for kanban view only
  fk_grp_col_id: string | null
}

const props = defineProps<Props>()

const emits = defineEmits<Emits>()

const inputEl = $ref<ComponentPublicInstance>()

const formValidator = $ref<typeof AntForm>()

const vModel = useVModel(props, 'modelValue', emits)

const { t } = useI18n()

const { isLoading: loading, api } = useApi()

const meta = inject(MetaInj, ref())

const viewList = inject(ViewListInj)

const form = reactive<Form>({
  title: props.title || '',
  type: props.type,
  copy_from_id: null,
  fk_grp_col_id: null,
})

const singleSelectFieldOptions = ref<SelectProps['options']>([])

const viewNameRules = [
  // name is required
  { required: true, message: `${t('labels.viewName')} ${t('general.required')}` },
  // name is unique
  {
    validator: (_: unknown, v: string) =>
      new Promise((resolve, reject) => {
        ;(unref(viewList) || []).every((v1) => ((v1 as GridType | KanbanType | GalleryType).alias || v1.title) !== v)
          ? resolve(true)
          : reject(new Error(`View name should be unique`))
      }),
    message: 'View name should be unique',
  },
]

const groupingFieldColumnRules = [
  // name is required
  { required: true, message: `${t('general.groupingField')} ${t('general.required')}` },
]

const typeAlias = computed(
  () =>
    ({
      [ViewTypes.GRID]: 'grid',
      [ViewTypes.GALLERY]: 'gallery',
      [ViewTypes.FORM]: 'form',
      [ViewTypes.KANBAN]: 'kanban',
    }[props.type]),
)

watch(vModel, (value) => value && init())

watch(
  () => props.type,
  (newType) => {
    form.type = newType
  },
)

function init() {
  form.title = generateUniqueTitle(capitalize(ViewTypes[props.type].toLowerCase()), viewList?.value || [], 'title')

  if (props.selectedViewId) {
    form.copy_from_id = props.selectedViewId
  }

  // preset the grouping field column
  if (props.type === ViewTypes.KANBAN) {
    singleSelectFieldOptions.value = meta
      .value!.columns!.filter((el) => el.uidt === UITypes.SingleSelect)
      .map((field) => {
        return {
          value: field.id,
          label: field.title,
        }
      })
    if (props.groupingFieldColumnId) {
      // take from the one from copy view
      form.fk_grp_col_id = props.groupingFieldColumnId
    } else {
      // take the first option
      form.fk_grp_col_id = singleSelectFieldOptions.value?.[0]?.value as string
    }
  }

  nextTick(() => {
    const el = inputEl?.$el as HTMLInputElement

    if (el) {
      el.focus()
      el.select()
    }
  })
}

async function onSubmit() {
  const isValid = await formValidator?.validateFields()

  if (isValid && form.type) {
    const _meta = unref(meta)

    if (!_meta || !_meta.id) return

    try {
      let data: GridType | KanbanType | GalleryType | FormType | null = null

      switch (form.type) {
        case ViewTypes.GRID:
          data = await api.dbView.gridCreate(_meta.id, form)
          break
        case ViewTypes.GALLERY:
          data = await api.dbView.galleryCreate(_meta.id, form)
          break
        case ViewTypes.FORM:
          data = await api.dbView.formCreate(_meta.id, form)
          break
        case ViewTypes.KANBAN:
          data = await api.dbView.kanbanCreate(_meta.id, form)
      }

      if (data) {
        // View created successfully
        message.success(t('msg.toast.createView'))

        emits('created', data)
      }
    } catch (e: any) {
      message.error(e.message)
    }

    vModel.value = false
  }
}
</script>

<template>
  <a-modal v-model:visible="vModel" class="!top-[35%]" :confirm-loading="loading" wrap-class-name="nc-modal-view-create">
    <template #title>
      {{ $t('general.create') }} <span class="text-capitalize">{{ typeAlias }}</span> {{ $t('objects.view') }}
    </template>

    <a-form ref="formValidator" layout="vertical" :model="form">
      <a-form-item :label="$t('labels.viewName')" name="title" :rules="viewNameRules">
        <a-input ref="inputEl" v-model:value="form.title" autofocus @keydown.enter="onSubmit" />
      </a-form-item>
      <a-form-item
        v-if="form.type === ViewTypes.KANBAN"
        :label="$t('general.groupingField')"
        name="fk_grp_col_id"
        :rules="groupingFieldColumnRules"
      >
        <a-select
          v-model:value="form.fk_grp_col_id"
          class="w-full nc-kanban-grouping-field-select"
          :options="singleSelectFieldOptions"
          :disabled="props.groupingFieldColumnId"
          placeholder="Select a Grouping Field"
          not-found-content="No Single Select Field can be found. Please create one first."
        />
      </a-form-item>
    </a-form>

    <template #footer>
      <a-button key="back" @click="vModel = false">{{ $t('general.cancel') }}</a-button>
      <a-button key="submit" type="primary" :loading="loading" @click="onSubmit">{{ $t('general.submit') }}</a-button>
    </template>
  </a-modal>
</template>