<script setup lang="ts">
// PhoneInput — country code picker + national digits input.
//
// Emits an E.164 string via v-model (e.g. "+233244123456"). Empty input
// emits an empty string. The country list covers the ~50 most likely
// origins for event guests; uncommon ones can still be typed by picking
// the closest country and entering the full number — the live preview
// shows the host what's being saved.
//
// Industry-standard UX: WhatsApp / Stripe / airline-booking pattern.

interface Country {
  code: string      // ISO-3166 alpha-2
  name: string
  dialCode: string  // includes leading "+"
}

// Curated list — alphabetical-by-name, weighted toward common GuestGuard
// audience (UK/EU + Africa + diaspora destinations). The host can always
// type the full international number into another country's row if their
// country isn't here, but most won't need to.
const COUNTRIES: Country[] = [
  { code: 'AR', name: 'Argentina', dialCode: '+54' },
  { code: 'AU', name: 'Australia', dialCode: '+61' },
  { code: 'AT', name: 'Austria', dialCode: '+43' },
  { code: 'BE', name: 'Belgium', dialCode: '+32' },
  { code: 'BR', name: 'Brazil', dialCode: '+55' },
  { code: 'CM', name: 'Cameroon', dialCode: '+237' },
  { code: 'CA', name: 'Canada', dialCode: '+1' },
  { code: 'CL', name: 'Chile', dialCode: '+56' },
  { code: 'CN', name: 'China', dialCode: '+86' },
  { code: 'CI', name: "Côte d'Ivoire", dialCode: '+225' },
  { code: 'DK', name: 'Denmark', dialCode: '+45' },
  { code: 'EG', name: 'Egypt', dialCode: '+20' },
  { code: 'ET', name: 'Ethiopia', dialCode: '+251' },
  { code: 'FI', name: 'Finland', dialCode: '+358' },
  { code: 'FR', name: 'France', dialCode: '+33' },
  { code: 'DE', name: 'Germany', dialCode: '+49' },
  { code: 'GH', name: 'Ghana', dialCode: '+233' },
  { code: 'HK', name: 'Hong Kong', dialCode: '+852' },
  { code: 'IN', name: 'India', dialCode: '+91' },
  { code: 'ID', name: 'Indonesia', dialCode: '+62' },
  { code: 'IE', name: 'Ireland', dialCode: '+353' },
  { code: 'IL', name: 'Israel', dialCode: '+972' },
  { code: 'IT', name: 'Italy', dialCode: '+39' },
  { code: 'JP', name: 'Japan', dialCode: '+81' },
  { code: 'KE', name: 'Kenya', dialCode: '+254' },
  { code: 'MY', name: 'Malaysia', dialCode: '+60' },
  { code: 'MX', name: 'Mexico', dialCode: '+52' },
  { code: 'MA', name: 'Morocco', dialCode: '+212' },
  { code: 'NL', name: 'Netherlands', dialCode: '+31' },
  { code: 'NZ', name: 'New Zealand', dialCode: '+64' },
  { code: 'NG', name: 'Nigeria', dialCode: '+234' },
  { code: 'NO', name: 'Norway', dialCode: '+47' },
  { code: 'PH', name: 'Philippines', dialCode: '+63' },
  { code: 'PL', name: 'Poland', dialCode: '+48' },
  { code: 'PT', name: 'Portugal', dialCode: '+351' },
  { code: 'RW', name: 'Rwanda', dialCode: '+250' },
  { code: 'SA', name: 'Saudi Arabia', dialCode: '+966' },
  { code: 'SN', name: 'Senegal', dialCode: '+221' },
  { code: 'SG', name: 'Singapore', dialCode: '+65' },
  { code: 'ZA', name: 'South Africa', dialCode: '+27' },
  { code: 'KR', name: 'South Korea', dialCode: '+82' },
  { code: 'ES', name: 'Spain', dialCode: '+34' },
  { code: 'SE', name: 'Sweden', dialCode: '+46' },
  { code: 'CH', name: 'Switzerland', dialCode: '+41' },
  { code: 'TW', name: 'Taiwan', dialCode: '+886' },
  { code: 'TZ', name: 'Tanzania', dialCode: '+255' },
  { code: 'TH', name: 'Thailand', dialCode: '+66' },
  { code: 'TR', name: 'Turkey', dialCode: '+90' },
  { code: 'AE', name: 'UAE', dialCode: '+971' },
  { code: 'UG', name: 'Uganda', dialCode: '+256' },
  { code: 'GB', name: 'United Kingdom', dialCode: '+44' },
  { code: 'US', name: 'United States', dialCode: '+1' },
]

// Longer dial codes first so "+1" doesn't shadow "+1...". Sorted once.
const SORTED_BY_DIAL = [...COUNTRIES].sort((a, b) => b.dialCode.length - a.dialCode.length)

const props = defineProps<{
  modelValue: string
  /** ISO-3166 alpha-2 to use as default. Browser locale is consulted if omitted. */
  defaultCountry?: string
}>()
const emit = defineEmits<{ (e: 'update:modelValue', value: string): void }>()

function findByCode(code: string): Country | undefined {
  return COUNTRIES.find((c) => c.code === code.toUpperCase())
}

function parsePhone(v: string): { country: Country | null; national: string } {
  if (!v) return { country: null, national: '' }
  const trimmed = v.trim().replace(/[\s\-()]/g, '')
  for (const c of SORTED_BY_DIAL) {
    if (trimmed.startsWith(c.dialCode)) {
      return { country: c, national: trimmed.slice(c.dialCode.length) }
    }
  }
  // Fall through: leading +XX didn't match anything (or no leading +).
  // Strip a leading + and a leading 0 from local-format numbers so the
  // host's national digits show up cleanly in the input.
  return { country: null, national: trimmed.replace(/^\+/, '').replace(/^0+/, '') }
}

function detectDefault(): Country {
  if (props.defaultCountry) {
    const c = findByCode(props.defaultCountry)
    if (c) return c
  }
  if (typeof navigator !== 'undefined' && navigator.language) {
    const region = navigator.language.split('-')[1] || ''
    const c = findByCode(region)
    if (c) return c
  }
  return findByCode('GB')!
}

const initial = parsePhone(props.modelValue)
const country = ref<Country>(initial.country || detectDefault())
const national = ref(initial.national)

// Digits the host typed, with leading 0s stripped (local-format helper).
const nationalDigits = computed(() => national.value.replace(/\D/g, '').replace(/^0+/, ''))

// E.164 composed from current state. Empty when no digits — keeps the
// stored value clean (don't save "+44" with no number).
const composed = computed(() => {
  return nationalDigits.value ? `${country.value.dialCode}${nationalDigits.value}` : ''
})

// Inline validation. We don't try to encode per-country length rules
// (that's libphonenumber's job and overkill here) — instead we apply a
// generous floor/ceiling on the national digit count. Catches obvious
// typos without false-positives on shorter formats like Iceland (+354 7).
type Validation = 'empty' | 'short' | 'long' | 'ok'
const validation = computed<Validation>(() => {
  const n = nationalDigits.value.length
  if (n === 0) return 'empty'
  if (n < 6) return 'short'
  if (n > 13) return 'long'
  return 'ok'
})

// Emit on user changes — guard reentrancy so an external prop update
// doesn't bounce back into our own watcher.
let emitting = false
watch(composed, (v) => {
  emitting = true
  emit('update:modelValue', v)
  Promise.resolve().then(() => { emitting = false })
})

// Re-sync from prop changes (e.g., parent resets the form, edit modal
// reopens for a different guest). Skip when our own emit caused it.
watch(() => props.modelValue, (v) => {
  if (emitting) return
  const p = parsePhone(v)
  if (p.country) country.value = p.country
  national.value = p.national
})

// Smart input: if the host pastes (or types) a full E.164 with leading
// "+" into the national field, extract the country code and split it
// into the picker + the national digits. Rescues the common mistake of
// pasting "+233244123456" into the digits field instead of using the
// picker — without this, the value would get double-prefixed.
function onNationalInput(e: Event) {
  const v = (e.target as HTMLInputElement).value
  if (v.startsWith('+')) {
    const parsed = parsePhone(v)
    if (parsed.country) {
      country.value = parsed.country
      national.value = parsed.national
      return
    }
  }
  national.value = v
}
</script>

<template>
  <div>
    <div class="flex gap-2">
      <select
        v-model="country"
        class="input w-28 shrink-0 cursor-pointer"
        aria-label="Country code"
      >
        <option v-for="c in COUNTRIES" :key="c.code" :value="c">
          {{ c.dialCode }} {{ c.code }}
        </option>
      </select>
      <input
        :value="national"
        @input="onNationalInput"
        type="tel"
        inputmode="tel"
        autocomplete="tel-national"
        class="input flex-1"
        :class="{
          'border-amber-700/60 focus:border-amber-500 focus:ring-amber-500': validation === 'short' || validation === 'long',
        }"
        placeholder="Phone number"
        :aria-invalid="validation === 'short' || validation === 'long' || undefined"
      />
    </div>
    <!-- Live feedback. Different message per validation state:
         empty  → optional hint
         short  → amber warning, hostsees it before pressing Save
         long   → amber warning
         ok     → green confirmation with the canonical E.164 visible -->
    <p class="mt-1 flex items-center gap-1 text-xs">
      <template v-if="validation === 'empty'">
        <span class="text-zinc-500">
          Optional — include the country code so guests on any network can be reached.
        </span>
      </template>
      <template v-else-if="validation === 'short'">
        <svg class="h-3.5 w-3.5 shrink-0 text-amber-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
          <path fill-rule="evenodd" d="M8.485 3.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 3.495zM10 8a1 1 0 01.993.883L11 9v3a1 1 0 01-1.993.117L9 12V9a1 1 0 011-1zm0 6a1 1 0 110 2 1 1 0 010-2z" clip-rule="evenodd" />
        </svg>
        <span class="text-amber-300">Looks too short — make sure you've entered all the digits.</span>
      </template>
      <template v-else-if="validation === 'long'">
        <svg class="h-3.5 w-3.5 shrink-0 text-amber-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
          <path fill-rule="evenodd" d="M8.485 3.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 3.495zM10 8a1 1 0 01.993.883L11 9v3a1 1 0 01-1.993.117L9 12V9a1 1 0 011-1zm0 6a1 1 0 110 2 1 1 0 010-2z" clip-rule="evenodd" />
        </svg>
        <span class="text-amber-300">Looks too long — check for extra digits.</span>
      </template>
      <template v-else>
        <svg class="h-3.5 w-3.5 shrink-0 text-brand-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
          <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
        </svg>
        <span class="text-zinc-500">
          Saved as <span class="font-mono text-zinc-300">{{ composed }}</span>
        </span>
      </template>
    </p>
  </div>
</template>
