<template>
  <v-row no-gutters class="mb-5">
    <v-col cols="12" class="d-flex ga-2">
      <v-select
        v-model="selectedCode"
        :variant="variant"
        :items="countries"
        item-title="code"
        item-value="code"
        hide-details
        class="px-0"
        :density="density"
        style="max-width: 95px"
        :rules="[...props.rules]"
        :readonly="props.readOnly"
        :disabled="props.disabled"
        @update:model-value="handleUpdateCountry"
      >
        <template v-slot:item="{ props: itemProps, item }">
          <v-list-item
            v-bind="itemProps"
            :title="item.raw.name"
            :subtitle="item.raw.dial_code"
          />
        </template>
      </v-select>

      <v-mask-input
        v-model="input"
        :mask="currentMask"
        :rules="[...props.rules, validatePhone]"
        ref="maskRef"
        :key="`mask-key-${maskKey}`"
        :loading="loading"
        :readonly="props.readOnly"
        :variant="variant"
        hint="Enter a valid phone number"
        hide-details
        persistent-hint
        return-masked-value
        :prefix="phonePrefix || ''"
        persistent-placeholder
        :density="density"
        :disabled="props.disabled"
        :placeholder="placeholder || currentMask"
      />
    </v-col>
    <span class="text-error text-caption w-100" v-if="errorMessage && !hideDetails">
      {{ errorMessage }}
    </span>
  </v-row>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted, type PropType } from 'vue'
//@ts-ignore
import phoneMasks from '~/utils/phoneMasks'
import type { ValidationRule } from 'vuetify/lib/types.mjs'

const props = defineProps({
  modelValue: { type: String as PropType<string>, default: '' },
  rules: { type: Array as PropType<ValidationRule[]>, default: () => [] },
  variant: { type: String as PropType<any>, default: 'outlined' },
  density: { type: String as PropType<'default' | 'comfortable' | 'compact'>, default: 'default' },
  placeholder: { type: String },
  hideDetails: { type: Boolean, default: false },
  loading: { type: Boolean, default: false },
  readOnly: { type: Boolean, default: false },
  disabled: { type: Boolean, default: false },
})

const emit = defineEmits(['update:modelValue'])

type TPhoneMask = {
  name: string
  flag: string
  code: string
  dial_code: string
  regex: string
}

// Main reactive values
const phone = ref(props.modelValue)
const input = ref('')
const selectedCode = ref('SG')
const countries = phoneMasks
const errorMessage = ref('')
const maskRef = ref()
const maskKey = ref(0)


const currentMask = computed(() => {
  const country = countries.find((c: TPhoneMask) => c.code === selectedCode.value)
  if (!country) return '############'
  return generateMaskFromRegex(country.regex)
})


const phonePrefix = computed(() => {
  const country = countries.find((c: TPhoneMask) => c.code === selectedCode.value)
  return country?.dial_code || ''
})

function generateMaskFromRegex(regex: string): string {
  let pattern = regex.replace(/^\^|\$$/g, '')
  pattern = pattern.replace(/\(\?:\+?\d+\)\?/g, '')
  pattern = pattern.replace(/\+?\d{1,4}/, '')
  pattern = pattern.replace(/\\d\{(\d+)\}/g, (_, count) => '#'.repeat(Number(count)))
  pattern = pattern.replace(/\\d/g, '#')
  pattern = pattern.replace(/\\/g, '')
  pattern = pattern.replace(/\(\?:/g, '')
  return pattern.trim()
}

const validatePhone = (): boolean | string => {
  if (props.readOnly) return true
  if (!phone.value) return true

  const country = countries.find((c: TPhoneMask) => c.code === selectedCode.value)
  if (!country) return true

  const regex = new RegExp(country.regex)
  const isValid = regex.test(phone.value)
  errorMessage.value = isValid ? '' : `Invalid ${country.name} phone number`
  return isValid
}

function handleUpdateCountry() {
  const prefix = phonePrefix.value
  if (phone.value?.startsWith(prefix)) {
    input.value = phone.value.slice(prefix.length)
  } else {
    input.value = ''
  }
}


watch(input, (newInput) => {
  const prefix = phonePrefix.value
  if (!newInput) phone.value = ''
  else phone.value = prefix + newInput
})

watch(
  () => props.modelValue,
  (val) => {
    phone.value = val || ''
  },
  { immediate: true }
)


watch(phone, (newVal) => {
  const prefix = phonePrefix.value
  if (!newVal) input.value = ''
  else input.value = newVal.startsWith(prefix) ? newVal.slice(prefix.length) : newVal
  emit('update:modelValue', newVal)
})


watch(selectedCode, () => {
  const prefix = phonePrefix.value
  if (phone.value?.startsWith(prefix)) input.value = phone.value.slice(prefix.length)
  else input.value = phone.value || ''
})


onMounted(() => {
  if (phone.value) {
    const found = countries.find((c: TPhoneMask) => phone.value.startsWith(c.dial_code))
    if (found) selectedCode.value = found.code
    const prefix = phonePrefix.value
    input.value = phone.value.startsWith(prefix) ? phone.value.slice(prefix.length) : phone.value
    maskKey.value++
  }
})
</script>
