import {
  createComponentFactory,
  Spectator,
  mockProvider,
} from '@ngneat/spectator/jest';
import { MockComponents } from 'ng-mocks';
import { FilterMenuButtonComponent } from './filter-menu-button.component';
import { FilterService } from '../../core';
import { Overlay } from '@angular/cdk/overlay';
import { FilterMenuComponent } from './filter-menu.component';
import { NgIconComponent } from '@ng-icons/core';
import { IconButtonComponent } from '@isa/ui/buttons';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

jest.mock('scandit-web-datacapture-core', () => ({}));
jest.mock('scandit-web-datacapture-barcode', () => ({}));

describe('FilterMenuButtonComponent', () => {
  let spectator: Spectator<FilterMenuButtonComponent>;
  let filterService: jest.Mocked<FilterService>;

  const createComponent = createComponentFactory({
    component: FilterMenuButtonComponent,
    declarations: [
      MockComponents(NgIconComponent, FilterMenuComponent, IconButtonComponent),
    ],
    componentProviders: [
      mockProvider(Overlay, { scrollStrategies: { block: jest.fn() } }),
    ],
    providers: [
      mockProvider(FilterService, {
        isDefaultFilter: jest.fn().mockReturnValue(true),
        rollback: jest.fn(),
        selectedFilterCount: jest.fn().mockReturnValue(0),
      }),
    ],
    schemas: [CUSTOM_ELEMENTS_SCHEMA],
    detectChanges: false,
  });

  beforeEach(() => {
    spectator = createComponent({
      props: {
        rollbackOnClose: false,
      },
    });
    spectator.detectChanges();

    filterService = spectator.inject(FilterService);
  });

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

  it('should toggle open state and emit events', () => {
    // Arrange
    const closedSpy = jest.spyOn(spectator.component.closed, 'emit');
    const openedSpy = jest.spyOn(spectator.component.opened, 'emit');

    // Act - Open
    spectator.component.toggle();

    // Assert - Open
    expect(spectator.component.open()).toBe(true);
    expect(openedSpy).toHaveBeenCalled();

    // Act - Close
    spectator.component.toggle();

    // Assert - Close
    expect(spectator.component.open()).toBe(false);
    expect(closedSpy).toHaveBeenCalled();
  });

  it('should rollback on close when rollbackOnClose is true', async () => {
    // Arrange
    spectator.setInput('rollbackOnClose', true);
    jest.useFakeTimers();

    // Act
    spectator.component.closed.emit();

    // Fast-forward timers
    jest.runAllTimers();

    // Assert
    expect(filterService.rollback).toHaveBeenCalled();

    // Clean up
    jest.useRealTimers();
  });

  it('should close menu when applied is emitted', () => {
    // Arrange
    spectator.component.open.set(true);

    // Act
    spectator.component.applied.emit();

    // Assert
    expect(spectator.component.open()).toBe(false);
  });
});
