<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { CircleAlert, CircleCheck, Search, Eye, Pencil, FileText, Download } from '@lucide/vue'
import dayjs from 'dayjs'
import * as select from '@zag-js/select'
import {
  AlertRoot,
  AlertTitle,
  AlertDescription,
  AlertCloseTrigger,
} from '@/components/ui/alert'
import { Badge } from '@/components/ui/badge'
import { CheckboxRoot, CheckboxControl } from '@/components/ui/checkbox'
import { Input } from '@/components/ui/input'
import {
  SelectRoot,
  SelectControl,
  SelectTrigger,
  SelectValueText,
  SelectContent,
  SelectItemGroup,
  SelectItemGroupLabel,
  SelectItem,
  SelectItemText,
} from '@/components/ui/select'
import { Button } from '@/components/ui/button'
import { DialogRoot, DialogContent, DialogCloseTrigger } from '@/components/ui/dialog'
import { Field, FieldError, FieldLabel } from '@/components/ui/field'
import DataTable from '@/components/ui/usage/DataTable.vue'
import type { TableHeader } from '@/components/ui/usage/DataTable.vue'
import { getApiErrorMessage, getApiValidationErrors } from '@/core/utils/getApiErrorMessage'
import axios from 'axios'
import { useMembershipApplicationList } from '../composables/useMembershipApplicationList'
import { usePermissions } from '@/composables/usePermissions'
import {
  batchCompleteMembershipApplications,
  downloadMembershipApplicationDocument,
  generateMembershipApplicationResultLetter,
} from '../services/membership-application.service'
import {
  boardResultBadgeVariant,
  statusBadgeLook,
  statusBadgeVariant,
} from '../utils/membership-application-badge.utils'
import type {
  BatchCompleteFailedItem,
  BatchCompleteResponse,
  GenerateResultLetterResponse,
  MembershipApplicationBoardResult,
  MembershipApplicationListItem,
  MembershipApplicationStatus,
} from '../types/membership-application.types'

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

const STATUS_FILTER_OPTIONS: SelectOption[] = [
  { label: 'Semua Status', value: '' },
  { label: 'Dihantar', value: 'SUBMITTED' },
  { label: 'Menunggu Lembaga', value: 'PENDING_BOARD' },
  { label: 'Ditolak Pentadbiran', value: 'MANAGEMENT_REJECTED' },
  { label: 'Menunggu Makluman', value: 'PENDING_NOTIFICATION' },
  { label: 'Selesai', value: 'COMPLETED' },
]

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

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

function apiValueToLabel(options: SelectOption[], value: string | null | undefined): string[] {
  if (value === '' || value === null || value === undefined) {
    const allOption = options.find((item) => item.value === '')
    return allOption ? [allOption.label] : []
  }

  const option = options.find((item) => item.value === value)
  return option ? [option.label] : []
}

const statusFilterCollection = createSelectCollection(STATUS_FILTER_OPTIONS)

const router = useRouter()
const { hasPermission } = usePermissions()

const {
  applications,
  loading,
  error,
  search,
  statusFilter,
  sortBy,
  page,
  itemsPerPage,
  pagination,
  handleSortUpdate,
  fetchApplications,
} = useMembershipApplicationList()

const canBatchComplete = computed(() => hasPermission('selesaikan permohonan keahlian'))
const canGenerateResultLetter = computed(() => hasPermission('jana surat keputusan keahlian'))
const selectedIds = ref<string[]>([])
const batchSubmitting = ref(false)
const batchConfirmOpen = ref(false)
const batchSuccessMessage = ref<string | null>(null)
const letterSuccessMessage = ref<string | null>(null)
const batchFailedItems = ref<BatchCompleteFailedItem[]>([])
const generateDialogOpen = ref(false)
const generateSubmitting = ref(false)
const boardMeetingReference = ref('')
const boardMeetingReferenceError = ref<string | null>(null)
const generateTarget = ref<MembershipApplicationListItem | null>(null)
const downloadingResultLetterId = ref<string | null>(null)

const selectableApplications = computed(() =>
  applications.value.filter((item) => item.status === 'PENDING_NOTIFICATION'),
)

const allSelectableSelected = computed(() => {
  const eligible = selectableApplications.value
  return eligible.length > 0 && eligible.every((item) => selectedIds.value.includes(item.id))
})

watch(applications, () => {
  selectedIds.value = selectedIds.value.filter((id) =>
    applications.value.some((item) => item.id === id && item.status === 'PENDING_NOTIFICATION'),
  )
})

function isSelectable(item: MembershipApplicationListItem): boolean {
  return item.status === 'PENDING_NOTIFICATION'
}

function isSelected(id: string): boolean {
  return selectedIds.value.includes(id)
}

function toggleSelection(id: string) {
  if (selectedIds.value.includes(id)) {
    selectedIds.value = selectedIds.value.filter((selectedId) => selectedId !== id)
    return
  }

  selectedIds.value = [...selectedIds.value, id]
}

function toggleSelectAllOnPage(checked: boolean) {
  if (!checked) {
    const pageIds = new Set(selectableApplications.value.map((item) => item.id))
    selectedIds.value = selectedIds.value.filter((id) => !pageIds.has(id))
    return
  }

  const merged = new Set([
    ...selectedIds.value,
    ...selectableApplications.value.map((item) => item.id),
  ])
  selectedIds.value = [...merged]
}

function openBatchConfirm() {
  if (!selectedIds.value.length) return
  batchConfirmOpen.value = true
}

async function confirmBatchComplete() {
  if (!selectedIds.value.length || batchSubmitting.value) return

  batchSubmitting.value = true
  batchSuccessMessage.value = null
  batchFailedItems.value = []
  error.value = null

  try {
    const response = await batchCompleteMembershipApplications(selectedIds.value)

    if (response.success) {
      batchSuccessMessage.value = response.message
      batchFailedItems.value = response.data.failed
      selectedIds.value = []
      batchConfirmOpen.value = false
      await fetchApplications(page.value)
    } else {
      error.value = response.message
      batchFailedItems.value = response.data.failed
    }
  } catch (err) {
    if (axios.isAxiosError(err) && err.response?.data) {
      const responseData = err.response.data as BatchCompleteResponse
      batchFailedItems.value = responseData.data?.failed ?? []
      error.value = responseData.message ?? getApiErrorMessage(err, 'Gagal menyelesaikan permohonan.')
    } else {
      error.value = getApiErrorMessage(err, 'Gagal menyelesaikan permohonan.')
    }
  } finally {
    batchSubmitting.value = false
  }
}

function setStatusFilterValue(details: { value: string[] }) {
  statusFilter.value = labelToApiValue(STATUS_FILTER_OPTIONS, details.value[0])
}

const statusFilterInitial = computed(() => apiValueToLabel(STATUS_FILTER_OPTIONS, statusFilter.value))

function statusLabel(status: MembershipApplicationStatus): string {
  const labels: Record<MembershipApplicationStatus, string> = {
    SUBMITTED: 'Dihantar',
    PENDING_BOARD: 'Menunggu Lembaga',
    MANAGEMENT_REJECTED: 'Ditolak Pentadbiran',
    PENDING_NOTIFICATION: 'Menunggu Makluman',
    COMPLETED: 'Selesai',
  }

  return labels[status] ?? status
}

function boardResultLabel(result: MembershipApplicationBoardResult | null): string {
  if (result === 'PASS') return 'Lulus'
  if (result === 'FAIL') return 'Gagal'
  return '-'
}

function formatSubmittedAt(value: string | null): string {
  if (!value) return '-'
  return dayjs(value).format('DD/MM/YYYY HH:mm')
}

function goToApplicationDetail(id: string) {
  router.push({ name: 'view-membership-application', params: { id } })
}

function goToApplicationEdit(id: string) {
  router.push({ name: 'edit-membership-application', params: { id } })
}

function canGenerateLetter(item: MembershipApplicationListItem): boolean {
  return (
    canGenerateResultLetter.value &&
    item.status === 'COMPLETED' &&
    !item.has_result_letter &&
    (item.board_result === 'PASS' || item.board_result === 'FAIL')
  )
}

function canDownloadLetter(item: MembershipApplicationListItem): boolean {
  return !!item.has_result_letter && !!item.result_letter_document
}

function openGenerateDialog(item: MembershipApplicationListItem) {
  generateTarget.value = item
  boardMeetingReference.value = ''
  boardMeetingReferenceError.value = null
  generateDialogOpen.value = true
}

function closeGenerateDialog() {
  if (generateSubmitting.value) return
  generateDialogOpen.value = false
  generateTarget.value = null
  boardMeetingReference.value = ''
  boardMeetingReferenceError.value = null
}

async function confirmGenerateLetter() {
  if (!generateTarget.value || generateSubmitting.value) return

  const reference = boardMeetingReference.value.trim()
  if (!reference) {
    boardMeetingReferenceError.value = 'Rujukan mesyuarat lembaga diperlukan.'
    return
  }

  generateSubmitting.value = true
  boardMeetingReferenceError.value = null
  error.value = null
  letterSuccessMessage.value = null

  try {
    const response = await generateMembershipApplicationResultLetter(generateTarget.value.id, {
      board_meeting_reference: reference,
    })

    letterSuccessMessage.value = response.message
    closeGenerateDialog()
    await fetchApplications(page.value)
  } catch (err) {
    if (axios.isAxiosError(err) && err.response?.data) {
      const responseData = err.response.data as GenerateResultLetterResponse
      const validationErrors = getApiValidationErrors(err)
      boardMeetingReferenceError.value = validationErrors?.board_meeting_reference?.[0] ?? null
      error.value = responseData.message ?? getApiErrorMessage(err, 'Gagal menjana surat keputusan.')
    } else {
      error.value = getApiErrorMessage(err, 'Gagal menjana surat keputusan.')
    }
  } finally {
    generateSubmitting.value = false
  }
}

async function handleDownloadResultLetter(item: MembershipApplicationListItem) {
  const document = item.result_letter_document
  if (!document) return

  downloadingResultLetterId.value = item.id

  try {
    await downloadMembershipApplicationDocument(
      item.id,
      document.id,
      document.name,
      document.mime_type,
    )
  } catch (err) {
    error.value = getApiErrorMessage(err, 'Gagal memuat turun surat keputusan.')
  } finally {
    downloadingResultLetterId.value = null
  }
}

const headers = computed<TableHeader[]>(() => {
  const base: TableHeader[] = [
    { title: 'Bil.', key: '#', sortable: false },
    { title: 'No. Permohonan', key: 'application_number', sortable: true },
    {
      title: 'Nama Pemohon',
      key: 'applicant_name',
      sortable: false,
      exportValue: (item) => item.applicant?.name ?? '',
    },
    {
      title: 'Emel',
      key: 'applicant_email',
      sortable: false,
      exportValue: (item) => item.applicant?.email ?? '',
    },
    {
      title: 'No. IC',
      key: 'applicant_ic_number',
      sortable: false,
      exportValue: (item) => item.applicant?.ic_number ?? '',
    },
    {
      title: 'Status',
      key: 'status',
      sortable: true,
      exportValue: (item) => statusLabel(item.status),
    },
    {
      title: 'Keputusan Lembaga',
      key: 'board_result',
      sortable: false,
      exportValue: (item) => boardResultLabel(item.board_result),
    },
    {
      title: 'Tarikh Hantar',
      key: 'submitted_at',
      sortable: true,
      exportValue: (item) => formatSubmittedAt(item.submitted_at),
    },
    { title: 'Tindakan', key: 'actions', sortable: false },
  ]

  if (canBatchComplete.value) {
    return [{ title: '', key: 'select', sortable: false, width: 48 }, ...base]
  }

  return base
})

</script>

<template>
  <div class="w-full space-y-6">
    <div>
      <h2 class="text-lg font-medium">Senarai Permohonan Keahlian</h2>
      <p class="mt-1 text-sm opacity-70">Urus dan semak permohonan keahlian koperasi.</p>
    </div>

    <AlertRoot v-if="letterSuccessMessage" variant="success">
      <CircleCheck />
      <AlertTitle>Berjaya</AlertTitle>
      <AlertDescription>{{ letterSuccessMessage }}</AlertDescription>
      <AlertCloseTrigger @click="letterSuccessMessage = null" />
    </AlertRoot>

    <AlertRoot v-if="batchSuccessMessage" variant="success">
      <CircleCheck />
      <AlertTitle>Berjaya</AlertTitle>
      <AlertDescription>{{ batchSuccessMessage }}</AlertDescription>
      <AlertCloseTrigger @click="batchSuccessMessage = null" />
    </AlertRoot>

    <AlertRoot v-if="batchFailedItems.length" variant="warning">
      <CircleAlert />
      <AlertTitle>Sebahagian Permohonan Gagal</AlertTitle>
      <AlertDescription>
        <ul class="mt-2 list-disc space-y-1 ps-4 text-left">
          <li v-for="item in batchFailedItems" :key="item.id">
            {{ item.application_number ?? item.id }}: {{ item.message }}
          </li>
        </ul>
      </AlertDescription>
      <AlertCloseTrigger @click="batchFailedItems = []" />
    </AlertRoot>

    <AlertRoot v-if="error" variant="danger">
      <CircleAlert />
      <AlertTitle>Ralat</AlertTitle>
      <AlertDescription>{{ error }}</AlertDescription>
      <AlertCloseTrigger @click="error = null" />
    </AlertRoot>

    <DataTable :headers="headers" :items="applications" :loading="loading" :pagination="pagination"
      :current-sort="sortBy" show-pagination exportable export-file-name="permohonan-keahlian" v-model:page="page"
      v-model:items-per-page="itemsPerPage" @update:sort-by="handleSortUpdate">
      <template #toolbar>
        <div class="flex w-full flex-wrap items-center gap-3">
          <div class="relative w-full max-w-md flex-1">
            <Search class="pointer-events-none absolute top-1/2 left-3 z-10 size-4 -translate-y-1/2 text-foreground/50"
              aria-hidden="true" />
            <Input v-model="search" type="search" placeholder="Cari no. permohonan, nama, emel, IC..."
              class="w-full pl-9" aria-label="Cari permohonan keahlian" />
          </div>

          <SelectRoot class="w-full sm:w-56" :collection="statusFilterCollection" :default-value="statusFilterInitial"
            @value-change="setStatusFilterValue">
            <SelectControl>
              <SelectTrigger aria-label="Tapis status">
                <SelectValueText placeholder="Semua Status" />
              </SelectTrigger>
            </SelectControl>
            <SelectContent>
              <SelectItemGroup>
                <SelectItemGroupLabel>Status</SelectItemGroupLabel>
                <SelectItem v-for="item in statusFilterCollection.items" :key="item.label" :item="item">
                  <SelectItemText>{{ item.label }}</SelectItemText>
                </SelectItem>
              </SelectItemGroup>
            </SelectContent>
          </SelectRoot>

          <template v-if="canBatchComplete">
            <Button type="button" look="outline" variant="secondary"
              :disabled="!selectableApplications.length || loading"
              @click="toggleSelectAllOnPage(!allSelectableSelected)">
              {{ allSelectableSelected ? 'Nyahpilih Halaman' : 'Pilih Halaman' }}
            </Button>
            <Button type="button" variant="primary" :disabled="!selectedIds.length || loading || batchSubmitting"
              @click="openBatchConfirm">
              Selesaikan Terpilih ({{ selectedIds.length }})
            </Button>
          </template>
        </div>
      </template>

      <template v-if="canBatchComplete" #item.select="{ item }">
        <CheckboxRoot v-if="isSelectable(item as MembershipApplicationListItem)"
          :checked="isSelected((item as MembershipApplicationListItem).id)"
          @checked-change="({ checked }) => toggleSelection((item as MembershipApplicationListItem).id)">
          <CheckboxControl />
        </CheckboxRoot>
      </template>

      <template #item.applicant_name="{ item }">
        <span class="font-medium">{{ (item as MembershipApplicationListItem).applicant?.name ?? '-' }}</span>
      </template>

      <template #item.applicant_email="{ item }">
        <span class="lowercase">{{ (item as MembershipApplicationListItem).applicant?.email ?? '-' }}</span>
      </template>

      <template #item.applicant_ic_number="{ item }">
        {{ (item as MembershipApplicationListItem).applicant?.ic_number ?? '-' }}
      </template>

      <template #item.status="{ item }">
        <Badge
          :variant="statusBadgeVariant((item as MembershipApplicationListItem).status)"
          :look="statusBadgeLook((item as MembershipApplicationListItem).status)"
          class="whitespace-nowrap"
        >
          {{ statusLabel((item as MembershipApplicationListItem).status) }}
        </Badge>
      </template>

      <template #item.board_result="{ item }">
        <Badge v-if="(item as MembershipApplicationListItem).board_result"
          :variant="boardResultBadgeVariant((item as MembershipApplicationListItem).board_result)"
          class="whitespace-nowrap">
          {{ boardResultLabel((item as MembershipApplicationListItem).board_result) }}
        </Badge>
        <span v-else class="opacity-50">-</span>
      </template>

      <template #item.submitted_at="{ item }">
        {{ formatSubmittedAt((item as MembershipApplicationListItem).submitted_at) }}
      </template>

      <template #item.actions="{ item }">
        <div class="flex items-center gap-2">
          <Button v-if="hasPermission('lihat permohonan keahlian')" type="button" variant="ghost" size="sm"
            class="bg-green-600 text-white" title="Lihat butiran permohonan"
            @click="goToApplicationDetail((item as MembershipApplicationListItem).id)">
            <Eye class="size-4" aria-hidden="true" />
          </Button>
          <Button v-if="hasPermission('kemaskini permohonan keahlian')" type="button" variant="ghost" size="sm"
            class="bg-blue-600 text-white" title="Kemaskini permohonan"
            @click="goToApplicationEdit((item as MembershipApplicationListItem).id)">
            <Pencil class="size-4" aria-hidden="true" />
          </Button>
          <Button
            v-if="canGenerateLetter(item as MembershipApplicationListItem)"
            type="button"
            variant="ghost"
            size="sm"
            class="bg-amber-600 text-white"
            title="Jana surat keputusan"
            @click="openGenerateDialog(item as MembershipApplicationListItem)"
          >
            <FileText class="size-4" aria-hidden="true" />
          </Button>
          <Button
            v-if="canDownloadLetter(item as MembershipApplicationListItem)"
            type="button"
            variant="ghost"
            size="sm"
            class="bg-purple-600 text-white"
            title="Muat turun surat keputusan"
            :disabled="downloadingResultLetterId === (item as MembershipApplicationListItem).id"
            @click="handleDownloadResultLetter(item as MembershipApplicationListItem)"
          >
            <Download class="size-4" aria-hidden="true" />
          </Button>
        </div>
      </template>
    </DataTable>

    <DialogRoot :open="batchConfirmOpen" @openChange="(details) => { batchConfirmOpen = details.open }">
      <DialogContent>
        <div class="p-5 text-center">
          <div class="mt-2 text-2xl font-medium">Selesaikan Permohonan Terpilih?</div>
          <div class="mt-2 opacity-70">
            {{ selectedIds.length }} permohonan akan diselesaikan dan e-mel keputusan dihantar.
          </div>
        </div>
        <div class="px-5 pb-8 text-center">
          <DialogCloseTrigger class="mr-2 w-32" :disabled="batchSubmitting">
            Batal
          </DialogCloseTrigger>
          <Button class="w-32" type="button" variant="primary" :disabled="batchSubmitting"
            @click="confirmBatchComplete">
            {{ batchSubmitting ? 'Memproses...' : 'Sahkan' }}
          </Button>
        </div>
      </DialogContent>
    </DialogRoot>

    <DialogRoot :open="generateDialogOpen" @openChange="(details) => { if (!details.open) closeGenerateDialog() }">
      <DialogContent>
        <div class="p-5">
          <div class="text-2xl font-medium">Jana Surat Keputusan</div>
          <p v-if="generateTarget" class="mt-2 text-sm opacity-70">
            {{ generateTarget.application_number }} · {{ generateTarget.applicant?.name ?? '-' }}
          </p>
          <Field class="mt-5">
            <FieldLabel for="board-meeting-reference">Rujukan Mesyuarat Lembaga</FieldLabel>
            <Input
              id="board-meeting-reference"
              v-model="boardMeetingReference"
              type="text"
              placeholder="Contoh: Mesyuarat Lembaga Bil. 3/2026"
              :disabled="generateSubmitting"
              @input="boardMeetingReferenceError = null"
            />
            <FieldError v-if="boardMeetingReferenceError">{{ boardMeetingReferenceError }}</FieldError>
          </Field>
          <p class="mt-3 text-sm opacity-70">
            Surat hanya boleh dijana sekali dan akan disimpan sebagai dokumen permohonan.
          </p>
        </div>
        <div class="px-5 pb-8 text-center">
          <DialogCloseTrigger class="mr-2 w-32" :disabled="generateSubmitting" @click="closeGenerateDialog">
            Batal
          </DialogCloseTrigger>
          <Button
            class="w-32"
            type="button"
            variant="primary"
            :disabled="generateSubmitting"
            @click="confirmGenerateLetter"
          >
            {{ generateSubmitting ? 'Menjana...' : 'Jana Surat' }}
          </Button>
        </div>
      </DialogContent>
    </DialogRoot>
  </div>
</template>
