<script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue'
import * as select from '@zag-js/select'
import { Button } from '@/components/ui/button'
import {
  DialogRoot,
  DialogContent,
  DialogTitle,
  DialogDescription,
  DialogCloseTrigger,
} from '@/components/ui/dialog'
import { Field, FieldLabel, FieldError } from '@/components/ui/field'
import { Input } from '@/components/ui/input'
import { Lucide } from '@/components/ui/lucide'
import {
  SelectRoot,
  SelectControl,
  SelectTrigger,
  SelectValueText,
  SelectContent,
  SelectItemGroup,
  SelectItem,
  SelectItemText,
} from '@/components/ui/select'
import { usePermissions } from '@/composables/usePermissions'
import { getApiErrorMessage, getApiValidationErrors } from '@/core/utils/getApiErrorMessage'
import { createActivityType, listActivityTypes } from '../services/activity.service'
import type { ActivityType } from '../types/activity.types'

type SelectOption = { label: string; value: string }

const model = defineModel<string>({ required: true })

const props = withDefaults(
  defineProps<{
    disabled?: boolean
    autoSelectFirst?: boolean
  }>(),
  {
    autoSelectFirst: false,
  },
)

const { hasPermission } = usePermissions()

const canCreateType = computed(() => hasPermission('tambah jenis aktiviti'))

const loading = ref(false)
const activityTypes = ref<ActivityType[]>([])
const selectKey = ref(0)
const selectInitial = ref<string[]>([])

const typeModalOpen = ref(false)
const typeName = ref('')
const typeCode = ref('')
const typeNameError = ref<string | null>(null)
const typeCodeError = ref<string | null>(null)
const savingType = ref(false)

function createSelectCollection(options: SelectOption[]) {
  return select.collection({
    items: options,
    itemToValue: (item) => item.label,
  })
}

function labelToValue(options: SelectOption[], label: string | undefined): string {
  if (!label) return options[0]?.value ?? ''
  return options.find((option) => option.label === label)?.value ?? ''
}

function valueToLabel(options: SelectOption[], value: string): string[] {
  const option = options.find((item) => item.value === value)
  return option ? [option.label] : []
}

function formatTypeLabel(type: ActivityType): string {
  return type.code ? `${type.name} (${type.code})` : type.name
}

const activityTypeOptions = computed<SelectOption[]>(() =>
  activityTypes.value.map((type) => ({
    label: formatTypeLabel(type),
    value: type.id,
  })),
)

const activityTypeCollection = computed(() =>
  createSelectCollection(activityTypeOptions.value),
)

function syncSelectInitial() {
  if (!model.value) {
    selectInitial.value = []
    return
  }

  selectInitial.value = valueToLabel(activityTypeOptions.value, model.value)
  selectKey.value += 1
}

function setActivityTypeValue(details: { value: string[] }) {
  model.value = labelToValue(activityTypeOptions.value, details.value[0])
}

function resetTypeForm() {
  typeName.value = ''
  typeCode.value = ''
  typeNameError.value = null
  typeCodeError.value = null
}

function openTypeModal() {
  resetTypeForm()
  typeModalOpen.value = true
}

function handleTypeModalOpenChange(details: { open: boolean }) {
  if (savingType.value && !details.open) {
    typeModalOpen.value = true
    return
  }

  typeModalOpen.value = details.open

  if (!details.open) {
    resetTypeForm()
  }
}

async function fetchActivityTypes() {
  loading.value = true

  try {
    activityTypes.value = await listActivityTypes()
    syncSelectInitial()

    if (props.autoSelectFirst && !model.value && activityTypes.value.length > 0) {
      model.value = activityTypes.value[0]!.id
      syncSelectInitial()
    }
  } catch {
    activityTypes.value = []
  } finally {
    loading.value = false
  }
}

async function handleCreateType() {
  if (savingType.value) return

  const trimmedName = typeName.value.trim()
  const trimmedCode = typeCode.value.trim()

  typeNameError.value = null
  typeCodeError.value = null

  if (!trimmedName) {
    typeNameError.value = 'Nama jenis aktiviti diperlukan.'
    return
  }

  savingType.value = true

  try {
    const created = await createActivityType({
      name: trimmedName,
      code: trimmedCode || null,
    })

    activityTypes.value = [...activityTypes.value, created]
    model.value = created.id
    syncSelectInitial()

    typeModalOpen.value = false
    resetTypeForm()
  } catch (err) {
    const validationErrors = getApiValidationErrors(err)
    if (validationErrors?.name?.[0]) {
      typeNameError.value = validationErrors.name[0]
    }
    if (validationErrors?.code?.[0]) {
      typeCodeError.value = validationErrors.code[0]
    }
    if (!typeNameError.value && !typeCodeError.value) {
      typeNameError.value = getApiErrorMessage(err, 'Gagal menambah jenis aktiviti.')
    }
  } finally {
    savingType.value = false
  }
}

watch(
  () => model.value,
  () => {
    if (activityTypes.value.length) {
      syncSelectInitial()
    }
  },
)

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

<template>
  <Field>
    <FieldLabel>Jenis Aktiviti</FieldLabel>
    <div class="flex items-start gap-2">
      <SelectRoot
        :key="selectKey"
        class="min-w-0 flex-1"
        :collection="activityTypeCollection"
        :default-value="selectInitial"
        :disabled="props.disabled || loading || !activityTypeOptions.length"
        @value-change="setActivityTypeValue"
      >
        <SelectControl>
          <SelectTrigger>
            <SelectValueText
              :placeholder="loading ? 'Memuatkan jenis aktiviti...' : 'Pilih jenis aktiviti'"
            />
          </SelectTrigger>
        </SelectControl>
        <SelectContent>
          <SelectItemGroup>
            <SelectItem
              v-for="item in activityTypeCollection.items"
              :key="item.value"
              :item="item"
            >
              <SelectItemText>{{ item.label }}</SelectItemText>
            </SelectItem>
          </SelectItemGroup>
        </SelectContent>
      </SelectRoot>

      <Button
        v-if="canCreateType"
        type="button"
        look="outline"
        variant="primary"
        class="shrink-0"
        :disabled="props.disabled || savingType"
        title="Tambah jenis aktiviti"
        @click="openTypeModal"
      >
        <Lucide class="size-4" icon="Plus" />
      </Button>
    </div>
  </Field>

  <DialogRoot :open="typeModalOpen" @openChange="handleTypeModalOpenChange">
    <DialogContent class="max-w-md">
      <DialogTitle>Tambah Jenis Aktiviti</DialogTitle>
      <DialogDescription>
        Daftar jenis aktiviti baharu untuk digunakan dalam borang ini.
      </DialogDescription>

      <form class="mt-4 space-y-4" @submit.prevent="handleCreateType">
        <Field>
          <FieldLabel for="activity-type-name">Nama</FieldLabel>
          <Input
            id="activity-type-name"
            v-model="typeName"
            placeholder="Contoh: Mesyuarat Agung"
            :disabled="savingType"
            required
          />
          <FieldError v-if="typeNameError">{{ typeNameError }}</FieldError>
        </Field>

        <Field>
          <FieldLabel for="activity-type-code">Kod</FieldLabel>
          <Input
            id="activity-type-code"
            v-model="typeCode"
            placeholder="Contoh: MA (pilihan)"
            :disabled="savingType"
          />
          <FieldError v-if="typeCodeError">{{ typeCodeError }}</FieldError>
        </Field>

        <div class="flex justify-end gap-2 pt-2">
          <DialogCloseTrigger look="outline" variant="secondary" :disabled="savingType">
            Batal
          </DialogCloseTrigger>
          <Button type="submit" variant="primary" :disabled="savingType">
            {{ savingType ? 'Menyimpan...' : 'Simpan' }}
          </Button>
        </div>
      </form>
    </DialogContent>
  </DialogRoot>
</template>
