"use client"

import { ChangeEvent, useEffect, useMemo, useState } from "react"

import { cn } from "@/lib/utils"
import { Input } from "@/components/ui/input"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { COUNTRY_DIAL_CODES, type CountryDialCode } from "@/lib/country-codes"

export type CountryOption = {
  code: string
  label: string
  dialCode: string
  flag: string
  maxDigits: number
  formatLocal: (digits: string) => string
}

const DEFAULT_COUNTRY_CODE = "BR"

function formatBrazilPhone(digits: string): string {
  const cleaned = digits.slice(0, 11)
  if (!cleaned) return ""
  const area = cleaned.slice(0, 2)
  const rest = cleaned.slice(2)
  if (cleaned.length <= 2) return `(${cleaned}`
  if (rest.length <= 4) return `(${area}) ${rest}`
  if (rest.length <= 8) return `(${area}) ${rest.slice(0, 4)}-${rest.slice(4)}`
  return `(${area}) ${rest.slice(0, 5)}-${rest.slice(5)}`
}

function formatUsPhone(digits: string): string {
  const cleaned = digits.slice(0, 10)
  if (!cleaned) return ""
  const area = cleaned.slice(0, 3)
  const rest = cleaned.slice(3)
  if (cleaned.length <= 3) return `(${cleaned}`
  if (rest.length <= 3) return `(${area}) ${rest}`
  return `(${area}) ${rest.slice(0, 3)}-${rest.slice(3)}`
}

function extractDigits(value?: string | null): string {
  return (value ?? "").replace(/\D+/g, "")
}

function findCountryByValue(value?: string | null): CountryOption {
  const digits = extractDigits(value)
  const dialDigits = extractDigits(DEFAULT_COUNTRY.dialCode)
  let matched: CountryOption = DEFAULT_COUNTRY
  let matchedLength = digits.startsWith(dialDigits) ? dialDigits.length : 0
  for (const option of COUNTRY_OPTIONS) {
    const optionDialDigits = extractDigits(option.dialCode)
    if (optionDialDigits.length === 0) continue
    if (digits.startsWith(optionDialDigits) && optionDialDigits.length > matchedLength) {
      matched = option
      matchedLength = optionDialDigits.length
    }
  }
  return matched
}

function toLocalDigits(value: string | null | undefined, country: CountryOption): string {
  const digits = extractDigits(value)
  const dialDigits = extractDigits(country.dialCode)
  return digits.startsWith(dialDigits) ? digits.slice(dialDigits.length) : digits
}

function formatStoredValue(country: CountryOption, localDigits: string): string {
  const trimmed = localDigits.trim()
  if (!trimmed) return ""
  const formattedLocal = country.formatLocal(trimmed)
  if (!formattedLocal) return country.dialCode
  return `${country.dialCode} ${formattedLocal}`.trim()
}

function placeholderFor(country: CountryOption): string {
  if (country.code === "BR") return "(11) 91234-5678"
  if (country.code === "US") return "(555) 123-4567"
  if (country.code === "CA") return "(416) 123-4567"
  return "Número de telefone"
}

function formatGenericPhone(digits: string): string {
  const cleaned = digits.slice(0, 15)
  if (!cleaned) return ""
  return cleaned.replace(/(\d{3,4})(?=\d)/g, "$1 ").trim()
}

function flagEmojiFor(code: string): string {
  if (!code || code.length !== 2) return "🏳️"
  const base = 127397
  const chars = Array.from(code.toUpperCase()).map((char) => base + char.charCodeAt(0))
  return String.fromCodePoint(...chars)
}

const regionDisplayNames =
  typeof Intl !== "undefined" && "DisplayNames" in Intl
    ? new Intl.DisplayNames(["pt-BR", "pt", "en"], { type: "region" })
    : null

const SPECIAL_FORMATS: Record<string, { maxDigits: number; formatLocal: (digits: string) => string }> = {
  BR: { maxDigits: 11, formatLocal: formatBrazilPhone },
  US: { maxDigits: 10, formatLocal: formatUsPhone },
  CA: { maxDigits: 10, formatLocal: formatUsPhone },
}

const COUNTRY_OPTIONS: CountryOption[] = COUNTRY_DIAL_CODES.map(({ code, name, dialCode }: CountryDialCode) => {
  const special = SPECIAL_FORMATS[code]
  return {
    code,
    label: regionDisplayNames?.of(code) ?? name ?? code,
    dialCode,
    flag: flagEmojiFor(code),
    maxDigits: special?.maxDigits ?? 15,
    formatLocal: special?.formatLocal ?? formatGenericPhone,
  }
}).sort((a, b) => a.label.localeCompare(b.label, "pt-BR"))

const DEFAULT_COUNTRY =
  COUNTRY_OPTIONS.find((option) => option.code === DEFAULT_COUNTRY_CODE) ?? COUNTRY_OPTIONS[0]

export function PhoneInput({ value, onChange, className, id, name }: PhoneInputProps) {
  const [selectedCountry, setSelectedCountry] = useState<CountryOption>(DEFAULT_COUNTRY)
  const [localDigits, setLocalDigits] = useState<string>("")

  useEffect(() => {
    const country = findCountryByValue(value)
    setSelectedCountry(country)
    setLocalDigits(toLocalDigits(value, country).slice(0, country.maxDigits))
  }, [value])

  const displayValue = useMemo(() => selectedCountry.formatLocal(localDigits), [selectedCountry, localDigits])

  const handleCountryChange = (code: string) => {
    const country = COUNTRY_OPTIONS.find((option) => option.code === code) ?? DEFAULT_COUNTRY
    setSelectedCountry(country)
    const limitedDigits = localDigits.slice(0, country.maxDigits)
    setLocalDigits(limitedDigits)
    const stored = formatStoredValue(country, limitedDigits)
    onChange?.(stored)
  }

  const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
    const raw = event.target.value
    const digits = extractDigits(raw).slice(0, selectedCountry.maxDigits)
    setLocalDigits(digits)
    const stored = formatStoredValue(selectedCountry, digits)
    onChange?.(stored)
  }

  return (
    <div className={cn("flex flex-col gap-2 sm:flex-row sm:items-center", className)}>
      <Select value={selectedCountry.code} onValueChange={handleCountryChange}>
        <SelectTrigger className="w-40">
          <SelectValue>
            <span className="inline-flex items-center gap-2">
              <span>{selectedCountry.flag}</span>
              <span className="text-sm font-medium text-foreground">{selectedCountry.dialCode}</span>
            </span>
          </SelectValue>
        </SelectTrigger>
        <SelectContent className="max-h-72 overflow-y-auto">
          {COUNTRY_OPTIONS.map((option) => (
            <SelectItem key={option.code} value={option.code}>
              <span className="inline-flex items-center gap-2">
                <span>{option.flag}</span>
                <span>{option.label}</span>
                <span className="text-muted-foreground">{option.dialCode}</span>
              </span>
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
      <Input
        id={id}
        name={name}
        type="tel"
        value={displayValue}
        onChange={handleInputChange}
        placeholder={placeholderFor(selectedCountry)}
        inputMode="tel"
      />
    </div>
  )
}

export type PhoneInputProps = {
  value?: string | null
  onChange?: (value: string) => void
  className?: string
  id?: string
  name?: string
}

export function formatPhoneDisplay(rawValue?: string | null): string | null {
  const trimmed = rawValue?.trim()
  if (!trimmed) return null
  const country = findCountryByValue(trimmed)
  const localDigits = toLocalDigits(trimmed, country)
  const formattedLocal = country.formatLocal(localDigits)
  if (!formattedLocal) return `${country.dialCode}`.trim()
  return `${country.dialCode} ${formattedLocal}`.trim()
}
