/*
 * Copyright (C) 2018 Robert Bosch GmbH Copyright (C) 2018 Robert Bosch Manufacturing Solutions GmbH, Germany. All rights reserved.
 */

import { Component, DebugElement, Injectable } from '@angular/core';
import {
  ComponentFixture,
  fakeAsync,
  flushMicrotasks,
  inject,
  TestBed,
  tick,
  waitForAsync,
} from '@angular/core/testing';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { By } from '@angular/platform-browser';
import { CommandbarInlinefilterComponent } from '../inlinefilter/commandbar-inlinefilter.component';
import { CommandbarItemVisibilityService } from '../item/commandbar-item-visibility.service';
import { CommandbarInlinefiltersComponent } from './commandbar-inlinefilters.component';
import { BreakpointObserver, MediaMatcher } from '@angular/cdk/layout';

@Component({
  template: ` <bci-commandbar-inlinefilters>
    <bci-commandbar-inlinefilter hide="lt-md">A</bci-commandbar-inlinefilter>
    <bci-commandbar-inlinefilter hide="lt-lg">B</bci-commandbar-inlinefilter>
    <bci-commandbar-inlinefilter hide="lt-xl">C</bci-commandbar-inlinefilter>
    <bci-commandbar-inlinefilter *ngIf="showConditionalItem">D</bci-commandbar-inlinefilter>
  </bci-commandbar-inlinefilters>`,
})
class TestComponent {
  showConditionalItem = false;
}

describe('CommandbarInlinefiltersComponent', () => {
  let fixture: ComponentFixture<TestComponent>;
  let testComponent: TestComponent;
  let component: CommandbarInlinefiltersComponent;
  let debugElement: DebugElement;

  let mediaMatcher: MockMediaMatcher;
  let breakpointObserver: BreakpointObserver;

  beforeEach(
    waitForAsync(() => {
      TestBed.configureTestingModule({
        declarations: [TestComponent, CommandbarInlinefiltersComponent, CommandbarInlinefilterComponent],
        imports: [MatMenuModule, MatIconModule],
        providers: [CommandbarItemVisibilityService],
      }).compileComponents();
    })
  );

  beforeEach(inject(
    [BreakpointObserver, MediaMatcher],
    (bm: BreakpointObserver, mm: MockMediaMatcher) => {
      breakpointObserver = bm;
      mediaMatcher = mm;
    },
  ));

  beforeEach(
    waitForAsync(() => {
      fixture = TestBed.createComponent(TestComponent);
      fixture.detectChanges();

      testComponent = fixture.componentInstance;
      debugElement = fixture.debugElement.query(By.css('bci-commandbar-inlinefilters'));
      component = debugElement.injector.get(CommandbarInlinefiltersComponent);
      component.ngAfterViewInit();
    })
  );

  it('should inject MediaObserver, ɵMockMatchMedia and Breakpoints', () => {
    expect(breakpointObserver).toBeDefined();
    expect(mediaMatcher).toBeDefined();
  });

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

  it('should hide lt-lg and lt-xl when md', fakeAsync(() => {
    expect(component.visibleItems.length).toBe(3);
    expect(component.hiddenItems.length).toBe(0);
  }));

  it('should be able to hide everything', fakeAsync(() => {
    component.updateView(0);
    component.updateView(0);
    component.updateView(0);

    expect(component.visibleItems.length).toBe(0);
    expect(component.hiddenItems.length).toBe(3);
  }));

  it('should also hide single hidden item', fakeAsync(() => {
    component.updateView(0);

    expect(component.visibleItems.length).toBe(2);
    expect(component.hiddenItems.length).toBe(1);
  }));

  it('should react to window resizing', fakeAsync(() => {
    expect(component.visibleItems.length).toBe(3);
    expect(component.hiddenItems.length).toBe(0);

    component.updateView(0);

    expect(component.visibleItems.length).toBe(2);
    expect(component.hiddenItems.length).toBe(1);
  }));

  it('should react to item changes', fakeAsync(() => {
    expect(component.visibleItems.length).toBe(3);
    expect(component.hiddenItems.length).toBe(0);

    testComponent.showConditionalItem = true;
    fixture.detectChanges();
    tick(100);
    flushMicrotasks();

    expect(component.visibleItems.length).toBe(4);
    expect(component.hiddenItems.length).toBe(0);
  }));

  /**
   * mock for testing BreakpointObserver
   */
  class MockMediaQueryList {
    constructor(public media: string, public matches: boolean) {}
 }

 /**
  * mock for testing BreakpointObserver
  */
 @Injectable()
 class MockMediaMatcher {
   private _queries = new Map<string, MockMediaQueryList>();

   clear() {
     this._queries.clear();
   }
 }
});
