import { Component, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { of } from 'rxjs';
import { UiSearchboxAutocompleteOptionDirective } from './ui-searchbox-autocomplete-option.directive';
import { UiSearchboxAutocompleteComponent } from './ui-searchbox-autocomplete.component';

@Component({
  selector: 'unit-test',
  template: `<ui-searchbox-autocomplete>
    <p uiSearchboxAutocompleteOption>Test Option 1</p>
    <p uiSearchboxAutocompleteOption>Test Option 2</p>
    <p uiSearchboxAutocompleteOption *ngIf="showOption">Test Option 3</p>
  </ui-searchbox-autocomplete>`,
})
export class TestComponent {
  showOption = false;

  @ViewChild(UiSearchboxAutocompleteComponent, { read: UiSearchboxAutocompleteComponent, static: true })
  searchboxAutocomplete: UiSearchboxAutocompleteComponent;

  constructor() {}
}

describe('UiSearchboxAutocompleteComponent', () => {
  let fixture: ComponentFixture<TestComponent>;
  let component: TestComponent;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [UiSearchboxAutocompleteComponent, UiSearchboxAutocompleteOptionDirective, TestComponent],
    }).compileComponents();

    fixture = TestBed.createComponent(TestComponent);
    component = fixture.componentInstance;
  });

  describe('ngAfterContentInit', () => {
    beforeEach(() => {
      spyOn(component.searchboxAutocomplete, 'registerOptionOnSelect').and.callThrough();

      fixture.detectChanges();
    });

    it('should call registerOptionOnSelect', () => {
      component.searchboxAutocomplete.ngAfterContentInit();
      expect(component.searchboxAutocomplete.registerOptionOnSelect).toHaveBeenCalled();
    });
    it('should subscribe to options.changes and call registerOptionSelect', async () => {
      component.showOption = true;
      fixture.detectChanges();

      expect(component.searchboxAutocomplete.registerOptionOnSelect).toHaveBeenCalled();
    });
  });

  describe('toggle', () => {
    it('should set show and call showChanged', () => {
      spyOn(component.searchboxAutocomplete, 'showChanged').and.callThrough();
      const expectedShowValue = !component.searchboxAutocomplete['show'];

      component.searchboxAutocomplete.toggle();

      expect(component.searchboxAutocomplete['show']).toEqual(expectedShowValue);
      expect(component.searchboxAutocomplete.showChanged).toHaveBeenCalledWith(component.searchboxAutocomplete['show']);
    });
  });

  describe('open', () => {
    it('should set show and call showChanged', () => {
      spyOn(component.searchboxAutocomplete, 'showChanged').and.callThrough();

      component.searchboxAutocomplete.open();

      expect(component.searchboxAutocomplete['show']).toEqual(true);
      expect(component.searchboxAutocomplete.showChanged).toHaveBeenCalledWith(component.searchboxAutocomplete['show']);
    });
  });

  describe('close', () => {
    it('should set show and call showChanged', () => {
      spyOn(component.searchboxAutocomplete, 'showChanged').and.callThrough();

      component.searchboxAutocomplete.close();

      expect(component.searchboxAutocomplete['show']).toEqual(false);
      expect(component.searchboxAutocomplete.showChanged).toHaveBeenCalledWith(component.searchboxAutocomplete['show']);
    });
  });

  describe('selectValue', () => {
    it('should call onSelect and close', () => {
      spyOn(component.searchboxAutocomplete, 'onSelect').and.callThrough();
      spyOn(component.searchboxAutocomplete, 'close').and.callThrough();

      const value = 'Test Value';
      component.searchboxAutocomplete.selectValue(value);
      expect(component.searchboxAutocomplete.onSelect).toHaveBeenCalledWith(value);
      expect(component.searchboxAutocomplete.close).toHaveBeenCalled();
    });
  });

  describe('Autocomplete Options', () => {
    const getOptions = () => fixture.debugElement.queryAll(By.css('[uiSearchboxAutocompleteOption]'));
    it('should show autocomplete options if show is set to true', () => {
      component.searchboxAutocomplete['show'] = true;
      fixture.detectChanges();

      const options = getOptions();
      expect(options.length).toBeTruthy();
    });
    it('should show not autocomplete options if show is set to false', () => {
      component.searchboxAutocomplete['show'] = false;
      fixture.detectChanges();

      const options = getOptions();
      expect(options.length).toBeFalsy();
    });
  });
});
