import React, { useEffect, useMemo, useState } from 'react';
import { buildClassName } from '../../shared/utils/class-util';
import { compact } from 'lodash';
import { Country } from '../types';

interface PhoneInputProps {
  name: string;
  required?: boolean;
  value?: string | number;
  label?: string;
  placeholder?: string;
  hasError?: boolean;
  extraClassName?: string;
  countries: Country[];
  countryIso2?: string; // Initial country selection (ISO2 code)
  onChange?: React.ChangeEventHandler<HTMLElement>;
  onBlur?: React.FocusEventHandler<HTMLElement>;
}

const normalize = (v?: string | number) => (v == null ? '' : String(v));

const parseCombined = (raw: string, countries: Country[]): { prefix: string; number: string } => {
  const value = normalize(raw).trim();
  if (!value) return { prefix: '', number: '' };

  // Try to match a known prefix at the start. Prefer longest match.
  const sorted = [...countries].sort((a, b) => b.phonePrefix.length - a.phonePrefix.length);
  const hit = sorted.find((c) => value.startsWith(c.phonePrefix));
  if (hit) {
    const rest = value
      .slice(hit.phonePrefix.length)
      .trim()
      .replace(/^[-\s]+/, '');
    return { prefix: hit.phonePrefix, number: rest };
  }

  // Fallback: split on first space if it looks like a +prefix number
  const m = value.match(/^(\+\d{1,4})[\s-]*(.*)$/);
  if (m) return { prefix: m[1], number: m[2] };

  return { prefix: '', number: value };
};

const PhoneInput: React.FC<PhoneInputProps> = ({
  name,
  required,
  value,
  label,
  placeholder,
  extraClassName,
  hasError,
  countries,
  countryIso2,
  onChange,
  onBlur
}) => {
  // Derive initial state from `value`
  const initialCountry = countries.find((c) => c.iso2 === countryIso2);

  const initial = useMemo(() => parseCombined(normalize(value), countries), [value, countries]);
  const [prefix, setPrefix] = useState<string>(initial.prefix);
  const [number, setNumber] = useState<string>(initial.number);

  // Keep state in sync if the parent changes `value`
  useEffect(() => {
    const parsed = !prefix && !number && initialCountry ? { prefix: initialCountry.phonePrefix, number: '' } : parseCombined(normalize(value), countries);
    if (parsed.prefix) setPrefix(parsed.prefix);
    if (parsed.number) setNumber(parsed.number);
  }, [value, countries, countryIso2]);

  const emitCombinedChange = (e: React.ChangeEvent<HTMLElement>, nextPrefix: string, nextNumber: string) => {
    // Combine with a space, unless the number already starts with a dash or space
    const combined = nextPrefix && nextNumber ? compact([nextPrefix, nextNumber]).join(' ') : null;
    onChange?.({
      ...e,
      type: 'change',
      target: { name, value: combined },
      currentTarget: { name, value: combined }
    } as any);
  };

  const handleCountryBlur = (e: React.FocusEvent<HTMLSelectElement>) => {
    onBlur?.(e);
  };

  const onCountryChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
    const next = e.target.value;
    setPrefix(next);
    emitCombinedChange(e, next, number);
  };

  const onPhoneChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const cleaned = e.target.value.replace(/[^\d\s-]/g, '');
    setNumber(cleaned);
    emitCombinedChange(e, prefix, cleaned);
  };

  const handleNumberBlur = (e: React.FocusEvent<HTMLInputElement>) => {
    onBlur?.(e);
  };

  // Ensure the select shows a reasonable default when prefix is empty
  const selectValue = prefix || '';

  return (
    <label className={buildClassName(['form__group', extraClassName, hasError && 'form__group--error'])}>
      {label && <span className="form__label">{compact([label, required && '*']).join(' ')}</span>}

      <div className="phone-input">
        <div className="dropdown">
          <select
            aria-label={label ? `${label} – country code` : 'Country calling code'}
            name={`${name}__country`}
            value={selectValue}
            onBlur={handleCountryBlur}
            onChange={onCountryChange}>
            <option value="" disabled></option>
            {countries?.map((option) => (
              <option key={option.iso2} value={option.phonePrefix}>
                {option.name} ({option.phonePrefix})
              </option>
            ))}
          </select>
        </div>

        <input
          aria-label={label ? `${label} – number` : 'Phone number'}
          name={`${name}__number`}
          type="tel"
          inputMode="tel"
          required={required}
          className="form__input"
          placeholder={placeholder}
          onChange={onPhoneChange}
          onBlur={handleNumberBlur}
          value={number}
        />

        {/* Hidden merged value to integrate with forms that expect a single field */}
        <input type="hidden" name={name} value={compact([prefix, number]).join(' ')} />
      </div>
    </label>
  );
};

export default PhoneInput;
