import { DateTimeFormat } from '../models/date-time-format';
import { DateTimeFormatterService } from './date-time-formatter.service';

describe('DateTimeFormatterService', () => {
  const isoDate = '2026-07-20T14:30:45.000Z';
  const utcOptions = { timeZone: 'UTC' } as const;
  let service: DateTimeFormatterService;

  beforeEach(() => {
    service = new DateTimeFormatterService();
  });

  it('formats an ISO UTC string using the default format', () => {
    expect(service.format(isoDate, utcOptions)).toBe('20 Jul 2026, 02:30 pm');
  });

  it('formats a JavaScript Date', () => {
    expect(service.format(new Date(isoDate), {
      format: DateTimeFormat.Date,
      timeZone: 'UTC'
    })).toBe('20 Jul 2026');
  });

  it('formats a numeric timestamp', () => {
    expect(service.format(Date.parse(isoDate), {
      format: DateTimeFormat.TimeWithSeconds,
      timeZone: 'UTC'
    })).toBe('02:30:45 pm');
  });

  it.each([
    [DateTimeFormat.Date, '20 Jul 2026'],
    [DateTimeFormat.ShortDate, '20/07/2026'],
    [DateTimeFormat.LongDate, 'Monday, 20 July 2026'],
    [DateTimeFormat.DateTime, '20 Jul 2026, 02:30 pm'],
    [DateTimeFormat.ShortDateTime, '20/07/2026, 02:30 pm'],
    [DateTimeFormat.LongDateTime, 'Monday, 20 July 2026 at 02:30:45 pm'],
    [DateTimeFormat.Time, '02:30 pm'],
    [DateTimeFormat.TimeWithSeconds, '02:30:45 pm'],
    [DateTimeFormat.MonthYear, 'July 2026'],
    [DateTimeFormat.Year, '2026']
  ])('formats %s using its predefined options', (format, expected) => {
    expect(service.format(isoDate, { format, timeZone: 'UTC' })).toBe(expected);
  });

  it.each([null, undefined, '', '   ', 'not-a-date'])(
    'returns the default fallback for %s',
    value => {
      expect(service.format(value)).toBe('—');
    }
  );

  it('uses a custom fallback', () => {
    expect(service.format('invalid', { fallback: 'N/A' })).toBe('N/A');
  });

  it('supports a custom locale', () => {
    expect(service.format(isoDate, {
      format: DateTimeFormat.ShortDate,
      locale: 'de-DE',
      timeZone: 'UTC'
    })).toBe('20.07.2026');
  });

  it('supports a valid IANA timezone', () => {
    expect(service.format(isoDate, {
      format: DateTimeFormat.Time,
      timeZone: 'Asia/Dubai'
    })).toBe('06:30 pm');
  });

  it('handles a day change caused by timezone conversion', () => {
    expect(service.format('2026-07-20T23:30:00.000Z', {
      format: DateTimeFormat.Date,
      timeZone: 'Asia/Dubai'
    })).toBe('21 Jul 2026');
  });

  it('returns the fallback instead of throwing for an invalid timezone', () => {
    expect(service.format(isoDate, { timeZone: 'Invalid/Timezone' })).toBe('—');
  });
});
