"use client";

import React, {
  forwardRef,
  useId,
  useMemo,
  useRef,
  useState,
  useCallback,
  useEffect,
} from "react";
import Input from "react-phone-number-input/input";
import {
  getCountries,
  getCountryCallingCode,
  isValidPhoneNumber as libIsValidPhoneNumber,
  type Country,
} from "react-phone-number-input";
import flags from "react-phone-number-input/flags";
import en from "react-phone-number-input/locale/en.json";
import examples from "libphonenumber-js/examples.mobile.json";
import { getExampleNumber, parsePhoneNumber, AsYouType } from "libphonenumber-js";
import { Popover as PopoverPrimitive } from "radix-ui";
import { Check, ChevronDown, Search, X } from "lucide-react";
import { cn } from "@/lib/utils";

export type CountryCode = Country;

export const DEFAULT_COUNTRY: CountryCode = "IN";

export interface CountryOption {
  code: CountryCode;
  name: string;
  callingCode: string;
}

/** Pre-computed and sorted list of all 240+ countries supported by the metadata. */
export const ALL_COUNTRIES: CountryOption[] = getCountries()
  .map((code) => ({
    code,
    name: en[code] || code,
    callingCode: getCountryCallingCode(code),
  }))
  .sort((a, b) => a.name.localeCompare(b.name));

/**
 * Returns a human-friendly example/placeholder number dynamically derived from
 * the official Google libphonenumber metadata for the specified country.
 */
export function getCountryPlaceholder(country: CountryCode): string {
  try {
    const example = getExampleNumber(country, examples);
    if (!example) return "";
    const intl = example.formatInternational();
    const calling = `+${getCountryCallingCode(country)}`;
    if (intl.startsWith(calling)) {
      return intl.slice(calling.length).trim();
    }
    return example.formatNational();
  } catch {
    return "";
  }
}

/**
 * Validates a telephone number using Google libphonenumber metadata.
 */
export function isValidPhoneNumber(
  value: string | undefined | null,
  country?: CountryCode,
): boolean {
  if (!value || !value.trim()) return false;
  try {
    if (value.startsWith("+")) {
      return libIsValidPhoneNumber(value);
    }
    return country ? libIsValidPhoneNumber(value, country) : libIsValidPhoneNumber(value);
  } catch {
    return false;
  }
}

/**
 * Normalizes phone numbers to canonical E.164 (e.g. "+919876543210").
 */
export function formatE164(value: string | undefined | null, country?: CountryCode): string {
  if (!value || !value.trim()) return "";
  const trimmed = value.trim();
  try {
    const parsed = parsePhoneNumber(trimmed, country);
    if (parsed && parsed.isValid()) {
      return parsed.number;
    }
    if (parsed) {
      return parsed.number;
    }
  } catch {
    // If parsePhoneNumber threw an exception, fall back to clean digits
  }
  const digits = trimmed.replace(/[^\d+]/g, "");
  if (digits.startsWith("+")) return digits;
  if (country) {
    const calling = getCountryCallingCode(country);
    return `+${calling}${digits}`;
  }
  return digits;
}

/**
 * Adapts existing phone digits intelligently when the user changes country.
 * Preserves the user's national digits without duplicate or corrupted calling codes.
 */
export function switchCountryValue(
  value: string | undefined | null,
  fromCountry: CountryCode,
  toCountry: CountryCode,
): string {
  if (!value || !value.trim()) return "";
  try {
    const parsed = parsePhoneNumber(value, fromCountry);
    if (parsed && parsed.nationalNumber) {
      const newCalling = getCountryCallingCode(toCountry);
      return `+${newCalling}${parsed.nationalNumber}`;
    }
  } catch {
    const digits = value.replace(/\D/g, "");
    if (digits) {
      const oldCalling = getCountryCallingCode(fromCountry);
      const stripped = digits.startsWith(oldCalling) ? digits.slice(oldCalling.length) : digits;
      const newCalling = getCountryCallingCode(toCountry);
      return `+${newCalling}${stripped}`;
    }
  }
  return "";
}

/** Legacy alias for backwards compatibility */
export const composePhone = formatE164;
export const phoneDigitsValid = isValidPhoneNumber;

export interface PhoneFieldProps {
  id?: string;
  label?: string;
  country: CountryCode;
  onCountryChange: (code: CountryCode) => void;
  value?: string;
  onChange?: (value: string) => void;
  onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;
  onFocus?: (e: React.FocusEvent<HTMLInputElement>) => void;
  name?: string;
  error?: string;
  helper?: React.ReactNode;
  disabled?: boolean;
  className?: string;
  autoComplete?: string;
}

export const PhoneField = forwardRef<HTMLInputElement, PhoneFieldProps>(function PhoneField(
  {
    id: externalId,
    label = "Phone (optional)",
    country = DEFAULT_COUNTRY,
    onCountryChange,
    value = "",
    onChange,
    onBlur,
    onFocus,
    name = "phone",
    error,
    helper,
    disabled = false,
    className,
    autoComplete = "tel",
  },
  forwardedRef,
) {
  const generatedId = useId();
  const id = externalId || generatedId;
  const [isOpen, setIsOpen] = useState(false);
  const [searchQuery, setSearchQuery] = useState("");
  const [isFocused, setIsFocused] = useState(false);

  const searchInputRef = useRef<HTMLInputElement>(null);
  const internalInputRef = useRef<HTMLInputElement | null>(null);

  const setMergedRef = useCallback(
    (node: HTMLInputElement | null) => {
      internalInputRef.current = node;
      if (typeof forwardedRef === "function") {
        forwardedRef(node);
      } else if (forwardedRef) {
        forwardedRef.current = node;
      }
    },
    [forwardedRef],
  );

  const callingCode = useMemo(() => {
    try {
      return getCountryCallingCode(country);
    } catch {
      return "91";
    }
  }, [country]);

  const countryName = useMemo(() => en[country] || country, [country]);

  const placeholder = useMemo(() => getCountryPlaceholder(country), [country]);

  const Flag = flags[country];

  // Auto-focus search input when country popover opens
  useEffect(() => {
    if (isOpen) {
      const timer = setTimeout(() => {
        searchInputRef.current?.focus();
      }, 50);
      return () => clearTimeout(timer);
    } else {
      setSearchQuery("");
    }
  }, [isOpen]);

  // Filter country list by name, ISO code, or dial code
  const filteredCountries = useMemo(() => {
    const query = searchQuery.trim().toLowerCase();
    if (!query) return ALL_COUNTRIES;
    const cleanQuery = query.replace(/^\+/, "");
    return ALL_COUNTRIES.filter(
      (c) =>
        c.name.toLowerCase().includes(query) ||
        c.code.toLowerCase() === query ||
        c.callingCode.includes(cleanQuery),
    );
  }, [searchQuery]);

  const handleCountrySelect = useCallback(
    (newCountry: CountryCode) => {
      if (newCountry !== country) {
        onCountryChange(newCountry);
      }
      setIsOpen(false);
      setSearchQuery("");
      // Return focus to phone input for seamless typing
      setTimeout(() => {
        internalInputRef.current?.focus();
      }, 50);
    },
    [country, onCountryChange],
  );

  const handleInputFocus = useCallback(
    (e: React.FocusEvent<HTMLInputElement>) => {
      setIsFocused(true);
      onFocus?.(e);
    },
    [onFocus],
  );

  const handleInputBlur = useCallback(
    (e: React.FocusEvent<HTMLInputElement>) => {
      setIsFocused(false);
      onBlur?.(e);
    },
    [onBlur],
  );

  const hasValue = Boolean(value && String(value).trim().length > 0);
  const describedBy = error ? `${id}-error` : `${id}-help`;

  return (
    <div className="relative">
      <div
        className={cn(
          "relative flex h-14 items-stretch rounded-xl border bg-background shadow-2xs transition-[border-color,box-shadow,background-color] duration-200",
          error
            ? "border-destructive focus-within:border-destructive focus-within:ring-1 focus-within:ring-destructive/60"
            : "border-border hover:border-foreground/30 focus-within:border-foreground focus-within:ring-1 focus-within:ring-foreground/70",
          disabled && "cursor-not-allowed opacity-55",
        )}
      >
        {/* Country Selector Popover */}
        <PopoverPrimitive.Root open={isOpen} onOpenChange={setIsOpen}>
          <PopoverPrimitive.Trigger asChild>
            <button
              type="button"
              disabled={disabled}
              aria-label={`Country calling code: ${countryName}, +${callingCode}. Click to choose country`}
              aria-haspopup="listbox"
              aria-expanded={isOpen}
              className="flex h-full items-center gap-1.5 border-r border-border/70 px-3 text-foreground transition-colors hover:bg-muted/40 focus-visible:bg-muted/60 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 select-none cursor-pointer shrink-0"
            >
              <span
                className="flex size-5 shrink-0 items-center overflow-hidden rounded-[2px] shadow-2xs [&_svg]:h-full [&_svg]:w-full [&_svg]:object-cover"
                aria-hidden="true"
              >
                {Flag ? <Flag title={countryName} /> : null}
              </span>
              <span className="font-mono text-xs font-semibold text-foreground sm:text-sm">
                +{callingCode}
              </span>
              <ChevronDown
                className={cn(
                  "size-3 text-muted-foreground transition-transform duration-200",
                  isOpen && "rotate-180",
                )}
                aria-hidden="true"
              />
            </button>
          </PopoverPrimitive.Trigger>

          <PopoverPrimitive.Portal>
            <PopoverPrimitive.Content
              align="start"
              sideOffset={6}
              collisionPadding={12}
              className="z-50 w-[min(calc(100vw-32px),320px)] rounded-2xl border border-border bg-popover p-2 text-popover-foreground shadow-xl outline-none motion-safe:animate-in motion-safe:fade-in motion-safe:zoom-in-95"
            >
              {/* Search Box */}
              <div className="relative mb-2">
                <Search
                  className="absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground"
                  aria-hidden="true"
                />
                <input
                  ref={searchInputRef}
                  type="text"
                  value={searchQuery}
                  onChange={(e) => setSearchQuery(e.target.value)}
                  placeholder="Search countries or dial codes…"
                  aria-label="Search countries"
                  className="h-9 w-full rounded-xl border border-border bg-muted/40 pl-8 pr-7 text-xs text-foreground placeholder:text-muted-foreground focus:border-foreground focus:bg-background focus:outline-none focus:ring-1 focus:ring-foreground/70"
                />
                {searchQuery && (
                  <button
                    type="button"
                    onClick={() => setSearchQuery("")}
                    className="absolute right-2 top-1/2 -translate-y-1/2 p-0.5 text-muted-foreground hover:text-foreground cursor-pointer"
                    aria-label="Clear country search"
                  >
                    <X className="size-3" />
                  </button>
                )}
              </div>

              {/* Country List */}
              <div
                role="listbox"
                aria-label="Countries list"
                className="max-h-60 overflow-y-auto space-y-0.5 pr-1 text-xs focus:outline-none"
              >
                {filteredCountries.length === 0 ? (
                  <p className="py-6 text-center text-xs text-muted-foreground">
                    No country found.
                  </p>
                ) : (
                  filteredCountries.map((c) => {
                    const isSelected = c.code === country;
                    const CountryFlag = flags[c.code];
                    return (
                      <button
                        key={c.code}
                        role="option"
                        aria-selected={isSelected}
                        type="button"
                        onClick={() => handleCountrySelect(c.code)}
                        className={cn(
                          "flex w-full items-center justify-between gap-2 rounded-lg px-2.5 py-2 text-left transition-colors cursor-pointer outline-none",
                          isSelected
                            ? "bg-muted font-semibold text-foreground"
                            : "text-foreground hover:bg-muted/60 focus-visible:bg-muted/60",
                        )}
                      >
                        <div className="flex items-center gap-2.5 truncate">
                          <span
                            className="flex size-4 shrink-0 items-center overflow-hidden rounded-[2px] shadow-2xs [&_svg]:h-full [&_svg]:w-full [&_svg]:object-cover"
                            aria-hidden="true"
                          >
                            {CountryFlag ? <CountryFlag title={c.name} /> : null}
                          </span>
                          <span className="truncate">{c.name}</span>
                          <span className="font-mono text-[11px] text-muted-foreground">
                            ({c.code})
                          </span>
                        </div>
                        <div className="flex items-center gap-1.5 shrink-0">
                          <span className="font-mono text-xs text-muted-foreground">
                            +{c.callingCode}
                          </span>
                          {isSelected && <Check className="size-3.5 text-foreground" />}
                        </div>
                      </button>
                    );
                  })
                )}
              </div>
            </PopoverPrimitive.Content>
          </PopoverPrimitive.Portal>
        </PopoverPrimitive.Root>

        {/* Number Input Container */}
        <div className="relative flex-1">
          <Input
            id={id}
            ref={setMergedRef}
            country={country}
            international
            value={value}
            onChange={(val) => onChange?.(val ?? "")}
            onFocus={handleInputFocus}
            onBlur={handleInputBlur}
            disabled={disabled}
            name={name}
            autoComplete={autoComplete}
            aria-invalid={error ? true : undefined}
            aria-describedby={describedBy}
            placeholder={isFocused || hasValue ? placeholder : " "}
            className={cn(
              "peer h-full w-full bg-transparent px-3.5 pb-1.5 pt-5 text-sm text-foreground focus:outline-none disabled:cursor-not-allowed",
              // When unfocused and empty, keep placeholder invisible for peer-placeholder-shown CSS float
              !isFocused && !hasValue
                ? "placeholder:text-transparent"
                : "placeholder:text-muted-foreground/60",
              className,
            )}
          />

          <label
            htmlFor={id}
            className={cn(
              "pointer-events-none absolute left-3.5 top-2 z-[1] origin-left text-[11px] font-medium text-muted-foreground transition-all duration-200 ease-out",
              "peer-placeholder-shown:top-1/2 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:text-sm peer-placeholder-shown:font-normal peer-focus:top-2 peer-focus:translate-y-0 peer-focus:text-[11px] peer-focus:font-medium",
              error ? "text-destructive" : "peer-focus:text-foreground",
            )}
          >
            {label}
          </label>
        </div>
      </div>

      {error ? (
        <p
          id={`${id}-error`}
          role="alert"
          className="mt-1.5 flex items-start gap-1.5 text-xs font-medium text-destructive motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-top-1"
        >
          {error}
        </p>
      ) : (
        <p id={`${id}-help`} className="mt-1.5 text-xs text-muted-foreground">
          {helper ?? (placeholder ? `e.g. ${placeholder}` : undefined)}
        </p>
      )}
    </div>
  );
});
