<script lang="ts" setup>
import { computed, onMounted, reactive, ref, watch } from 'vue'
import * as select from '@zag-js/select'
import Swal from 'sweetalert2'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { Box } from '@/components/ui/box'
import { CheckboxRoot, CheckboxControl, CheckboxLabel } from '@/components/ui/checkbox'
import { Field, FieldError, FieldGroup, FieldLabel } from '@/components/ui/field'
import { Input } from '@/components/ui/input'
import { Lucide } from '@/components/ui/lucide'
import {
  SelectRoot,
  SelectControl,
  SelectTrigger,
  SelectValueText,
  SelectContent,
  SelectItemGroup,
  SelectItemGroupLabel,
  SelectItem,
  SelectItemText,
} from '@/components/ui/select'
import { getApiErrorMessage, getApiValidationErrors } from '@/core/utils/getApiErrorMessage'
import {
  createEmployment,
  deleteEmployment,
  listEmployments,
  updateEmployment,
} from '@/modules/profile/services/employment.service'
import type { Employment, EmploymentPayload } from '@/modules/profile/types/employment.types'
import { EMPLOYERS } from '@/constants/employers'

defineProps<{
  embedded?: boolean
}>()

const employments = ref<Employment[]>([])
const loadingEmployments = ref(false)
const savingEmployment = ref(false)
const deletingEmploymentId = ref<string | null>(null)
const editingEmploymentId = ref<string | null>(null)

type EmploymentFieldKey =
  | 'company_name'
  | 'job_title'
  | 'employment_type'
  | 'salary'
  | 'start_date'
  | 'end_date'
  | 'is_current'

const EMPLOYMENT_FIELD_KEYS: EmploymentFieldKey[] = [
  'company_name',
  'job_title',
  'employment_type',
  'salary',
  'start_date',
  'end_date',
  'is_current',
]

const employmentErrors = reactive<Partial<Record<EmploymentFieldKey, string>>>({})

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

const EMPLOYMENT_TYPE_OPTIONS: SelectOption[] = [
  { label: 'Tetap', value: 'Permanent' },
  { label: 'Kontrak', value: 'Contract' },
  { label: 'Percubaan', value: 'Trial' },
  { label: 'Sambilan', value: 'Part-time' },
]

const COMPANY_OPTIONS: SelectOption[] = EMPLOYERS.map((employer) => ({
  label: employer.name,
  value: employer.name,
}))

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

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

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

const employmentTypeCollection = createSelectCollection(EMPLOYMENT_TYPE_OPTIONS)
const companyNameCollection = createSelectCollection(COMPANY_OPTIONS)

const employmentTypeValue = ref<string[]>([])
const employmentTypeInitial = ref<string[]>([])
const companyNameValue = ref<string[]>([])
const companyNameInitial = ref<string[]>([])

function clearEmploymentFieldError(field: EmploymentFieldKey) {
  delete employmentErrors[field]
}

function clearEmploymentErrors() {
  for (const field of EMPLOYMENT_FIELD_KEYS) {
    delete employmentErrors[field]
  }
}

function setEmploymentErrorsFromApi(error: unknown): boolean {
  const apiErrors = getApiValidationErrors(error)
  if (!apiErrors) return false

  for (const [field, messages] of Object.entries(apiErrors)) {
    if (EMPLOYMENT_FIELD_KEYS.includes(field as EmploymentFieldKey) && messages[0]) {
      employmentErrors[field as EmploymentFieldKey] = messages[0]
    }
  }

  return Object.keys(employmentErrors).length > 0
}

function toDateInputValue(value: string | null | undefined): string {
  if (!value) return ''
  return value.slice(0, 10)
}

function emptyEmploymentForm() {
  return {
    company_name: '',
    job_title: '',
    employment_type: '',
    salary: '',
    start_date: '',
    end_date: '',
    is_current: true,
  }
}

const employmentForm = reactive(emptyEmploymentForm())

const employmentTypeLabel = computed(() =>
  Object.fromEntries(EMPLOYMENT_TYPE_OPTIONS.map((option) => [option.value, option.label])),
)

const isEditingEmployment = computed(() => editingEmploymentId.value !== null)

const canAddEmployment = computed(() => !loadingEmployments.value && employments.value.length === 0)

const showEmploymentForm = computed(() => isEditingEmployment.value || canAddEmployment.value)

function setEmploymentTypeValue(details: { value: string[] }) {
  employmentTypeValue.value = details.value
  clearEmploymentFieldError('employment_type')
  employmentForm.employment_type =
    labelToApiValue(EMPLOYMENT_TYPE_OPTIONS, details.value[0]) ?? ''
}

function setCompanyNameValue(details: { value: string[] }) {
  companyNameValue.value = details.value
  clearEmploymentFieldError('company_name')
  employmentForm.company_name = details.value[0] ?? ''
}

function syncEmploymentSelectValues() {
  employmentTypeValue.value = apiValueToLabel(EMPLOYMENT_TYPE_OPTIONS, employmentForm.employment_type)
  employmentTypeInitial.value = [...employmentTypeValue.value]
  companyNameValue.value = apiValueToLabel(COMPANY_OPTIONS, employmentForm.company_name)
  companyNameInitial.value = [...companyNameValue.value]
}

function resetEmploymentForm() {
  Object.assign(employmentForm, emptyEmploymentForm())
  editingEmploymentId.value = null
  clearEmploymentErrors()
  syncEmploymentSelectValues()
}

function formatSalary(value: number | string | null | undefined): string {
  const amount = Number(value)
  if (Number.isNaN(amount)) return '-'
  return new Intl.NumberFormat('ms-MY', {
    style: 'currency',
    currency: 'MYR',
    minimumFractionDigits: 2,
  }).format(amount)
}

function formatDateLabel(value: string | null | undefined): string {
  if (!value) return ''
  const date = new Date(value)
  if (Number.isNaN(date.getTime())) return value
  return new Intl.DateTimeFormat('ms-MY', {
    day: 'numeric',
    month: 'short',
    year: 'numeric',
  }).format(date)
}

function formatEmploymentPeriod(employment: Employment): string {
  const start = formatDateLabel(employment.start_date)
  if (employment.is_current) {
    return `${start} - Kini`
  }
  const end = formatDateLabel(employment.end_date)
  return end ? `${start} - ${end}` : start
}

function validateEmploymentForm(): boolean {
  clearEmploymentErrors()

  let valid = true

  if (!companyNameValue.value[0]?.trim()) {
    employmentErrors.company_name = 'Nama syarikat diperlukan.'
    valid = false
  }

  if (!employmentForm.job_title.trim()) {
    employmentErrors.job_title = 'Jawatan diperlukan.'
    valid = false
  }

  if (
    !employmentTypeValue.value[0] ||
    !labelToApiValue(EMPLOYMENT_TYPE_OPTIONS, employmentTypeValue.value[0])
  ) {
    employmentErrors.employment_type = 'Jenis kerja diperlukan.'
    valid = false
  }

  const salary = Number(employmentForm.salary)
  if (!employmentForm.salary.toString().trim() || Number.isNaN(salary) || salary < 0) {
    employmentErrors.salary = 'Gaji diperlukan.'
    valid = false
  }

  if (!employmentForm.start_date) {
    employmentErrors.start_date = 'Tarikh mula diperlukan.'
    valid = false
  }

  if (!employmentForm.is_current && !employmentForm.end_date) {
    employmentErrors.end_date = 'Tarikh tamat diperlukan jika bukan pekerjaan semasa.'
    valid = false
  }

  if (
    !employmentForm.is_current &&
    employmentForm.start_date &&
    employmentForm.end_date &&
    employmentForm.end_date < employmentForm.start_date
  ) {
    employmentErrors.end_date = 'Tarikh tamat mesti selepas tarikh mula.'
    valid = false
  }

  return valid
}

function buildEmploymentPayload(): EmploymentPayload {
  return {
    company_name: employmentForm.company_name.trim(),
    job_title: employmentForm.job_title.trim(),
    employment_type:
      labelToApiValue(EMPLOYMENT_TYPE_OPTIONS, employmentTypeValue.value[0]) ??
      employmentForm.employment_type,
    salary: Number(employmentForm.salary),
    start_date: employmentForm.start_date,
    end_date: employmentForm.is_current ? null : employmentForm.end_date || null,
    is_current: employmentForm.is_current,
  }
}

async function fetchEmployments() {
  loadingEmployments.value = true

  try {
    const res = await listEmployments()
    employments.value = res.data
  } catch (error) {
    await Swal.fire({
      icon: 'error',
      title: 'Ralat',
      text: getApiErrorMessage(error, 'Gagal memuatkan pekerjaan.'),
    })
  } finally {
    loadingEmployments.value = false
  }
}

function startEditEmployment(employment: Employment) {
  clearEmploymentErrors()
  editingEmploymentId.value = employment.id
  employmentForm.company_name = employment.company_name
  employmentForm.job_title = employment.job_title
  employmentForm.employment_type = employment.employment_type
  employmentForm.salary = String(employment.salary)
  employmentForm.start_date = toDateInputValue(employment.start_date)
  employmentForm.end_date = toDateInputValue(employment.end_date)
  employmentForm.is_current = employment.is_current
  syncEmploymentSelectValues()
}

async function onSaveEmployment() {
  if (!validateEmploymentForm()) {
    return
  }

  savingEmployment.value = true
  const wasEditing = isEditingEmployment.value
  const payload = buildEmploymentPayload()

  try {
    const res = wasEditing
      ? await updateEmployment(editingEmploymentId.value!, payload)
      : await createEmployment(payload)

    if (!res.success) {
      throw new Error(res.message ?? 'Gagal menyimpan pekerjaan.')
    }

    await fetchEmployments()
    resetEmploymentForm()

    await Swal.fire({
      toast: true,
      position: 'top-end',
      icon: 'success',
      title: wasEditing ? 'Pekerjaan berjaya dikemas kini.' : 'Pekerjaan berjaya ditambah.',
      showConfirmButton: false,
      timer: 3000,
    })
  } catch (error) {
    if (!setEmploymentErrorsFromApi(error)) {
      await Swal.fire({
        icon: 'error',
        title: 'Ralat',
        text: getApiErrorMessage(error, 'Gagal menyimpan pekerjaan.'),
      })
    }
  } finally {
    savingEmployment.value = false
  }
}

async function onDeleteEmployment(employment: Employment) {
  const result = await Swal.fire({
    icon: 'warning',
    title: 'Padam pekerjaan?',
    text: 'Tindakan ini tidak boleh dibatalkan.',
    showCancelButton: true,
    confirmButtonText: 'Padam',
    cancelButtonText: 'Batal',
  })

  if (!result.isConfirmed) return

  deletingEmploymentId.value = employment.id

  try {
    const res = await deleteEmployment(employment.id)

    if (!res.success) {
      throw new Error(res.message ?? 'Gagal memadam pekerjaan.')
    }

    if (editingEmploymentId.value === employment.id) {
      resetEmploymentForm()
    }

    await fetchEmployments()

    await Swal.fire({
      toast: true,
      position: 'top-end',
      icon: 'success',
      title: 'Pekerjaan berjaya dipadam.',
      showConfirmButton: false,
      timer: 3000,
    })
  } catch (error) {
    await Swal.fire({
      icon: 'error',
      title: 'Ralat',
      text: getApiErrorMessage(error, 'Gagal memadam pekerjaan.'),
    })
  } finally {
    deletingEmploymentId.value = null
  }
}

watch(
  () => employmentForm.is_current,
  (isCurrent) => {
    if (isCurrent) {
      employmentForm.end_date = ''
      clearEmploymentFieldError('end_date')
    }
  },
)

onMounted(async () => {
  syncEmploymentSelectValues()
  await fetchEmployments()
})
</script>

<template>
  <div :class="embedded ? '' : 'mt-5'">
    <Box raised="single" class="p-6">
      <div class="space-y-6">
        <div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
          <div>
            <h3 class="text-lg font-semibold text-slate-900">Pekerjaan</h3>
            <p class="mt-1 text-sm text-slate-500">
              Urus sejarah dan maklumat pekerjaan anda.
            </p>
          </div>
        </div>

        <div v-if="loadingEmployments" class="text-sm text-slate-500">
          Memuatkan pekerjaan...
        </div>

        <div v-else-if="employments.length" class="space-y-3">
          <div v-for="employment in employments" :key="employment.id"
            class="flex flex-col gap-4 rounded-lg border border-foreground/10 p-4 sm:flex-row sm:items-start sm:justify-between">
            <div class="min-w-0 flex-1">
              <div class="flex flex-wrap items-center gap-2">
                <span class="font-medium text-slate-900">{{ employment.company_name }}</span>
                <Badge class="bg-green-500 text-white" v-if="employment.is_current">Semasa</Badge>
                <Badge look="outline">
                  {{ employmentTypeLabel[employment.employment_type] ?? employment.employment_type }}
                </Badge>
              </div>
              <p class="mt-1 text-sm font-medium text-slate-700">{{ employment.job_title }}</p>
              <p class="mt-1 text-sm text-slate-500">{{ formatEmploymentPeriod(employment) }}</p>
              <p class="mt-1 text-sm text-slate-500">{{ formatSalary(employment.salary) }}</p>
            </div>
            <div class="flex shrink-0 gap-2">
              <Button type="button" variant="ghost" class="border border-foreground/15 shadow-none"
                :disabled="deletingEmploymentId === employment.id" @click="startEditEmployment(employment)">
                <Lucide class="mr-2 size-4" icon="Pencil" />
                Kemaskini
              </Button>
              <Button type="button" variant="ghost" class="border border-foreground/15 shadow-none text-danger"
                :disabled="deletingEmploymentId === employment.id" @click="onDeleteEmployment(employment)">
                <Lucide class="mr-2 size-4" :icon="deletingEmploymentId === employment.id ? 'LoaderCircle' : 'Trash'"
                  :class="{ 'animate-spin': deletingEmploymentId === employment.id }" />
                Padam
              </Button>
            </div>
          </div>
        </div>

        <div v-else class="rounded-lg border border-dashed border-foreground/15 p-6 text-center text-sm text-slate-500">
          Tiada pekerjaan direkodkan.
        </div>

        <form v-if="showEmploymentForm" class="space-y-6 border-t border-foreground/10 pt-6"
          @submit.prevent="onSaveEmployment">
          <div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
            <div>
              <h4 class="text-base font-semibold text-slate-900">
                {{ isEditingEmployment ? 'Kemaskini Pekerjaan' : 'Tambah Pekerjaan' }}
              </h4>
              <p class="mt-1 text-sm text-slate-500">
                {{
                  isEditingEmployment
                    ? 'Kemas kini maklumat pekerjaan yang dipilih.'
                    : 'Tambah rekod pekerjaan baharu ke profil anda.'
                }}
              </p>
            </div>
            <div class="flex gap-2">
              <Button v-if="isEditingEmployment" type="button" variant="ghost"
                class="border border-foreground/15 shadow-none" :disabled="savingEmployment"
                @click="resetEmploymentForm">
                Batal
              </Button>
              <Button type="submit" variant="primary" :disabled="savingEmployment">
                {{ savingEmployment ? 'Menyimpan...' : isEditingEmployment ? 'Kemaskini' : 'Tambah' }}
              </Button>
            </div>
          </div>

          <FieldGroup>
            <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
              <Field>
                <FieldLabel>Nama Syarikat</FieldLabel>
                <SelectRoot :key="`company-name-${editingEmploymentId ?? 'new'}`" class="w-full"
                  :collection="companyNameCollection" :default-value="companyNameInitial" :disabled="savingEmployment"
                  @value-change="setCompanyNameValue">
                  <SelectControl>
                    <SelectTrigger :aria-invalid="!!employmentErrors.company_name">
                      <SelectValueText placeholder="Pilih syarikat" />
                    </SelectTrigger>
                  </SelectControl>
                  <SelectContent>
                    <SelectItemGroup>
                      <SelectItemGroupLabel>Nama Syarikat</SelectItemGroupLabel>
                      <SelectItem v-for="item in companyNameCollection.items" :key="item.label" :item="item">
                        <SelectItemText>{{ item.label }}</SelectItemText>
                      </SelectItem>
                    </SelectItemGroup>
                  </SelectContent>
                </SelectRoot>
                <FieldError v-if="employmentErrors.company_name">{{ employmentErrors.company_name }}</FieldError>
              </Field>
              <Field>
                <FieldLabel for="employment-job-title">Jawatan</FieldLabel>
                <Input id="employment-job-title" v-model="employmentForm.job_title" type="text" placeholder="Jawatan"
                  :aria-invalid="!!employmentErrors.job_title" @input="clearEmploymentFieldError('job_title')" />
                <FieldError v-if="employmentErrors.job_title">{{ employmentErrors.job_title }}</FieldError>
              </Field>
              <Field>
                <FieldLabel>Jenis Kerja</FieldLabel>
                <SelectRoot :key="`employment-type-${editingEmploymentId ?? 'new'}`" class="w-full"
                  :collection="employmentTypeCollection" :default-value="employmentTypeInitial"
                  :disabled="savingEmployment" @value-change="setEmploymentTypeValue">
                  <SelectControl>
                    <SelectTrigger :aria-invalid="!!employmentErrors.employment_type">
                      <SelectValueText placeholder="Pilih jenis kerja" />
                    </SelectTrigger>
                  </SelectControl>
                  <SelectContent>
                    <SelectItemGroup>
                      <SelectItemGroupLabel>Jenis Kerja</SelectItemGroupLabel>
                      <SelectItem v-for="item in employmentTypeCollection.items" :key="item.label" :item="item">
                        <SelectItemText>{{ item.label }}</SelectItemText>
                      </SelectItem>
                    </SelectItemGroup>
                  </SelectContent>
                </SelectRoot>
                <FieldError v-if="employmentErrors.employment_type">
                  {{ employmentErrors.employment_type }}
                </FieldError>
              </Field>
              <Field>
                <FieldLabel for="employment-salary">Gaji (RM)</FieldLabel>
                <Input id="employment-salary" v-model="employmentForm.salary" type="number" min="0" step="0.01"
                  placeholder="0.00" :aria-invalid="!!employmentErrors.salary"
                  @input="clearEmploymentFieldError('salary')" />
                <FieldError v-if="employmentErrors.salary">{{ employmentErrors.salary }}</FieldError>
              </Field>
              <Field>
                <FieldLabel for="employment-start-date">Tarikh Mula Perkhidmatan</FieldLabel>
                <Input id="employment-start-date" v-model="employmentForm.start_date" type="date"
                  :aria-invalid="!!employmentErrors.start_date" @input="clearEmploymentFieldError('start_date')" />
                <FieldError v-if="employmentErrors.start_date">{{ employmentErrors.start_date }}</FieldError>
              </Field>
              <Field>
                <FieldLabel for="employment-end-date">Tarikh Tamat Perkhidmatan</FieldLabel>
                <Input id="employment-end-date" v-model="employmentForm.end_date" type="date"
                  :disabled="employmentForm.is_current" :aria-invalid="!!employmentErrors.end_date"
                  @input="clearEmploymentFieldError('end_date')" />
                <FieldError v-if="employmentErrors.end_date">{{ employmentErrors.end_date }}</FieldError>
              </Field>
              <Field class="md:col-span-2">
                <CheckboxRoot :checked="employmentForm.is_current" :disabled="savingEmployment"
                  @checked-change="({ checked }) => (employmentForm.is_current = checked === true)">
                  <CheckboxControl />
                  <CheckboxLabel>Pekerjaan semasa</CheckboxLabel>
                </CheckboxRoot>
              </Field>
            </div>
          </FieldGroup>
        </form>
      </div>
    </Box>
  </div>
</template>
