import { describe, expect, it } from 'vitest';
import { exceedsMaxLength, formatNational, maxNationalLength, nextNationalDigits, optionalPhoneNumber, phoneNumber, toE164, toNationalDigits } from './phone';
import { AsYouType, parsePhoneNumberFromString } from 'libphonenumber-js';

describe('phoneNumber', () => {
  it('normalizes a legacy Ethiopian national number to E.164', () => {
    expect(phoneNumber.parse('0911223344')).toBe('+251911223344');
  });

  it('passes an Ethiopian E.164 number through unchanged', () => {
    expect(phoneNumber.parse('+251911223344')).toBe('+251911223344');
  });

  it('accepts a valid international number', () => {
    expect(phoneNumber.parse('+14155552671')).toBe('+14155552671');
  });

  it('rejects a too-short number', () => {
    expect(() => phoneNumber.parse('+251911')).toThrow();
  });

  it('rejects non-numeric input', () => {
    expect(() => phoneNumber.parse('abc')).toThrow('Enter a valid phone number');
  });

  it('reports a blank value as missing, not invalid', () => {
    expect(() => phoneNumber.parse('')).toThrow('Phone number is required');
  });
});

describe('optionalPhoneNumber', () => {
  it('allows a blank value', () => {
    expect(optionalPhoneNumber.parse('')).toBe('');
  });

  it('still validates a non-blank value', () => {
    expect(() => optionalPhoneNumber.parse('abc')).toThrow();
  });
});

describe('typing helpers', () => {
  // Regression: an incomplete number doesn't parse, and an earlier version
  // collapsed it to '' — the box emptied on every keystroke.
  it('keeps partial digits as the number is typed one character at a time', () => {
    let display = '';
    let value = '';
    for (const ch of '911223344') {
      const digits = nextNationalDigits(display + ch, display);
      display = new AsYouType('ET').input(digits);
      value = toE164(digits, 'ET');
    }
    expect(display).toBe('911223344');
    expect(value).toBe('+251911223344');
  });

  it('drops a digit when a keystroke only removed a formatting character', () => {
    // "(415)" backspaced to "(415" leaves the digits unchanged.
    expect(nextNationalDigits('(415', '(415)')).toBe('41');
  });

  it('keeps the deleted digit count when a real digit is removed', () => {
    expect(nextNationalDigits('91122334', '911223344')).toBe('91122334');
  });

  it('reads the national part back out of a stored E.164 value', () => {
    expect(toNationalDigits('+251911223344', 'ET')).toBe('911223344');
    expect(toNationalDigits('+14155552671', 'US')).toBe('4155552671');
    expect(toNationalDigits('', 'ET')).toBe('');
  });

  it('falls back to a dial-code concatenation while the number is incomplete', () => {
    expect(toE164('9', 'ET')).toBe('+2519');
    expect(toE164('', 'ET')).toBe('');
  });
});

describe('trunk prefix and country code entered into the number box', () => {
  // The box holds the national part next to a "+251" selector, so a trunk 0
  // or a typed country code must be absorbed, not shown (and doubled) there.
  const cases: Array<[string, string]> = [
    ['0911111111', '911111111'],
    ['251911111111', '911111111'],
    ['911111111', '911111111'],
  ];
  it.each(cases)('normalizes %s to the national number %s', (typed, national) => {
    const parsed = parsePhoneNumberFromString(typed.replace(/\D/g, ''), 'ET');
    expect(parsed?.nationalNumber).toBe(national);
  });

  it.each(cases)('yields a valid E.164 value for %s', (typed) => {
    expect(phoneNumber.parse(typed)).toBe('+251911111111');
  });

  it('accepts a pasted +251 number', () => {
    expect(phoneNumber.parse('+251911666666')).toBe('+251911666666');
  });
});

describe('formatNational', () => {
  it('groups digits without the dial code or trunk prefix', () => {
    expect(formatNational('911223344', 'ET')).toBe('91 122 3344');
    expect(formatNational('4155552671', 'US')).toBe('415 555 2671');
    expect(formatNational('91', 'ET')).toBe('91');
    expect(formatNational('', 'ET')).toBe('');
  });

  it('keeps digits intact when the number does not format', () => {
    expect(formatNational('0911223344', 'ET').replace(/\D/g, '')).toBe('0911223344');
  });
});

describe('legacy stored values', () => {
  it('shows a national record without the trunk prefix', () => {
    expect(toNationalDigits('0911223344', 'ET')).toBe('911223344');
  });
});

describe('length limit', () => {
  it('reports the longest national number per country', () => {
    expect(maxNationalLength('ET')).toBe(9);
    expect(maxNationalLength('US')).toBe(10);
  });

  it('flags digits past the limit, counting the national part only', () => {
    expect(exceedsMaxLength('911223344', 'ET')).toBe(false);
    expect(exceedsMaxLength('9112233445', 'ET')).toBe(true);
    expect(exceedsMaxLength('0911223344', 'ET')).toBe(false);
    expect(exceedsMaxLength('251911223344', 'ET')).toBe(false);
    expect(exceedsMaxLength('09112233445', 'ET')).toBe(true);
  });
});
