import {
  createComponentFactory,
  Spectator,
  mockProvider,
} from '@ngneat/spectator/jest';
import { MockComponents, MockDirectives } from 'ng-mocks';
import { FilterInputMenuButtonComponent } from './input-menu-button.component';
import { FilterInput, FilterService } from '../../core';
import {
  CdkConnectedOverlay,
  CdkOverlayOrigin,
  Overlay,
} from '@angular/cdk/overlay';
import { FilterInputMenuComponent } from './input-menu.component';
import { NgIconComponent } from '@ng-icons/core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

describe('FilterInputMenuButtonComponent', () => {
  let spectator: Spectator<FilterInputMenuButtonComponent>;
  const dummyFilterInput: FilterInput = { label: 'Test Filter' } as FilterInput;

  let filterService: jest.Mocked<FilterService>;

  const createComponent = createComponentFactory({
    component: FilterInputMenuButtonComponent,

    declarations: [
      MockComponents(NgIconComponent, FilterInputMenuComponent),
      MockDirectives(CdkOverlayOrigin, CdkConnectedOverlay),
    ],
    componentProviders: [
      mockProvider(Overlay, { scrollStrategies: { block: jest.fn() } }),
    ],
    providers: [
      mockProvider(FilterService, {
        isDefaultFilterInput: jest.fn().mockReturnValue(true),
        commit: jest.fn(),
      }),
    ],
    schemas: [CUSTOM_ELEMENTS_SCHEMA],
    detectChanges: false,
  });

  beforeEach(() => {
    spectator = createComponent({
      props: {
        filterInput: dummyFilterInput,
        commitOnClose: 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 commit on close when commitOnClose is true', () => {
    // Arrange
    spectator.setInput('commitOnClose', true);
    spectator.component.open.set(true);

    // Act
    spectator.component.toggle();

    // Assert
    expect(filterService.commit).toHaveBeenCalled();
  });

  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);
  });
});
