import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
import { SelectedRangeComponent } from './selected-range.component';
import { RangeDatepicker } from '../../range-datepicker';
import { ReactiveFormsModule } from '@angular/forms';
import { DateInputDirective } from './date-input.directive';

describe('SelectedRangeComponent', () => {
  let spectator: Spectator<SelectedRangeComponent>;
  let component: SelectedRangeComponent;
  let rangeDatepickerMock: jest.Mocked<RangeDatepicker>;

  const testDate1 = new Date(2023, 0, 15); // Jan 15, 2023
  const testDate2 = new Date(2023, 1, 20); // Feb 20, 2023

  // Stub default dates for min and max
  const defaultMinDate = new Date(2022, 0, 1);
  const defaultMaxDate = new Date(2023, 11, 31);

  const createComponent = createComponentFactory({
    component: SelectedRangeComponent,
    imports: [ReactiveFormsModule, DateInputDirective],
    providers: [
      {
        provide: RangeDatepicker,
        useValue: {
          value: jest.fn(),
          setValue: jest.fn(),
          min: jest.fn().mockReturnValue(defaultMinDate),
          max: jest.fn().mockReturnValue(defaultMaxDate),
        },
      },
    ],
  });

  beforeEach(() => {
    rangeDatepickerMock = {
      value: jest.fn().mockReturnValue(undefined),
      setValue: jest.fn(),
      min: jest.fn().mockReturnValue(defaultMinDate),
      max: jest.fn().mockReturnValue(defaultMaxDate),
    } as unknown as jest.Mocked<RangeDatepicker>;

    spectator = createComponent({
      providers: [
        {
          provide: RangeDatepicker,
          useValue: rangeDatepickerMock,
        },
      ],
    });
    component = spectator.component;
  });

  it('should create the component', () => {
    expect(component).toBeTruthy();
  });

  it('should initialize form with values from rangeDatepicker', () => {
    // Arrange
    const startDate = testDate1;
    const endDate = testDate2;
    rangeDatepickerMock.value.mockReturnValue([startDate, endDate]);

    // Act
    component.form = component.createForm();
    spectator.detectChanges();

    // Assert
    expect(component.form.get('start')?.value).toBe(startDate);
    expect(component.form.get('stop')?.value).toBe(endDate);
  });

  it('should update datepicker value when form is valid', () => {
    // Arrange
    jest.spyOn(component.form, 'valid', 'get').mockReturnValue(true);
    // Set the form control values directly with Date objects.
    component.form.controls.start.setValue(testDate1);
    component.form.controls.stop.setValue(testDate2);

    spectator.detectChanges();

    // Assert
    expect(rangeDatepickerMock.setValue).toHaveBeenCalledWith([
      testDate1,
      testDate2,
    ]);
  });

  it('should not update datepicker value when form is invalid', async () => {
    // Arrange
    component.form.controls.start.setErrors({ required: true });
    component.form.controls.stop.setErrors({ required: true });
    jest.spyOn(component.form, 'valid', 'get').mockReturnValue(false);

    await new Promise((resolve) => setTimeout(resolve, 0));

    // Assert: now expecting update with undefined values.
    expect(rangeDatepickerMock.setValue).toHaveBeenCalledWith([
      undefined,
      undefined,
    ]);
  });
});
