import { Component, ViewChild } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { UiSearchboxAutocompleteComponent } from './ui-searchbox-autocomplete.component';
import { UiSearchboxComponent } from './ui-searchbox.component';
import { UiSearchboxModule } from './ui-searchbox.module';

// #region TestComponent
@Component({
  selector: 'unit-test',
  template: `
    <ui-searchbox>
      <input uiSearchboxInput />
      <ui-searchbox-warning>Unit Test</ui-searchbox-warning>
      <button uiSearchboxSearchButton>Search</button>
      <ui-searchbox-autocomplete></ui-searchbox-autocomplete>
    </ui-searchbox>
  `,
})
export class TestComponent {
  @ViewChild(UiSearchboxComponent, { read: UiSearchboxComponent, static: true })
  searchboxComponent: UiSearchboxComponent;

  constructor() {}
}
// #endregion

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

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

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

  describe('selectOption', () => {
    it('should call UiSearchboxInputDirective.setValue', fakeAsync(() => {
      fixture.detectChanges();
      tick();
      spyOn(fixture.componentInstance.searchboxComponent.input, 'setValue');
      fixture.componentInstance.searchboxComponent.selectOption('My Option');

      expect(fixture.componentInstance.searchboxComponent.input.setValue).toHaveBeenCalledWith('My Option');
    }));
  });

  describe('input', () => {
    it('should render the input Element', fakeAsync(() => {
      fixture.detectChanges();
      tick();
      const inputElement = fixture.debugElement.query(By.css('[uisearchboxinput]'));
      expect(inputElement).not.toBeNull();
    }));
  });

  describe('warning', () => {
    it('should render the warning Component', fakeAsync(() => {
      fixture.detectChanges();
      tick();
      const warningElement = fixture.debugElement.query(By.css('ui-searchbox-warning'));
      expect(warningElement).not.toBeNull();
    }));
  });

  describe('search button', () => {
    it('should render the search button Element', fakeAsync(() => {
      fixture.detectChanges();
      tick();
      const searchButton = fixture.debugElement.query(By.css('[uisearchboxsearchbutton]'));
      expect(searchButton).not.toBeNull();
    }));
  });

  describe('autocomplete', () => {
    it('should render the autocomplete Component', fakeAsync(() => {
      fixture.detectChanges();
      tick();
      const autocompleteElement = fixture.debugElement.query(By.css('ui-searchbox-autocomplete'));
      expect(autocompleteElement).not.toBeNull();
    }));
  });

  describe('autocomplete-visible class', () => {
    it('should add the class when autocomplete.show it true', fakeAsync(() => {
      fixture.detectChanges();
      tick();

      fixture.componentInstance.searchboxComponent.autocomplete.open();

      fixture.detectChanges();
      tick();

      const element = fixture.debugElement.query(By.css('.autocomplete-visible'));
      expect(element).not.toBeNull();
    }));
  });

  describe('ngAfterContentInit', () => {
    it('should register an onSelect and onShowChanges function', fakeAsync(() => {
      fixture.detectChanges();
      tick();

      spyOn(fixture.componentInstance.searchboxComponent.autocomplete, 'registerOnSelect').and.callThrough();
      spyOn(fixture.componentInstance.searchboxComponent.autocomplete, 'registerOnShowChanged').and.callThrough();

      fixture.componentInstance.searchboxComponent.ngAfterContentInit();

      expect(fixture.componentInstance.searchboxComponent.autocomplete.registerOnSelect).toHaveBeenCalled();
      expect(fixture.componentInstance.searchboxComponent.autocomplete.registerOnShowChanged).toHaveBeenCalled();
    }));
  });
});
