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

import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { MatSidenavModule } from '@angular/material/sidenav';
import { By } from '@angular/platform-browser';
import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations';
import { RouterTestingModule } from '@angular/router/testing';
import { Subject } from 'rxjs';
import { first } from 'rxjs/operators';
import { ModalWindowService } from '../../core/modal-window/modal-window.service';
import { ResizeHandleComponent } from '../resize-handle/resize-handle.component';
import { DetailViewComponent } from './detail/detail-view.component';
import { MasterDetailViewComponent } from './master-detail-view.component';

class MatDialogMock {
  s = new Subject<void>();
  backdropClick$ = new Subject<MouseEvent>();
  keydownEvents$ = new Subject<KeyboardEvent>();

  openDialogs = [];

  open() {
    return {
      beforeClose: () => this.s.asObservable(),
      afterClosed: () => this.s.asObservable(),
      backdropClick: () => this.backdropClick$.asObservable(),
      keydownEvents: () => this.keydownEvents$,
      close: () => {
        this.s.next();
      },
    };
  }
}

describe.skip('MasterDetailViewComponent', () => {
  let component: MasterDetailViewComponent;
  let fixture: ComponentFixture<MasterDetailViewComponent>;
  let modalWindowService: ModalWindowService;
  let spyOpenDialog: jest.SpyInstance;
  let closed: boolean;

  beforeEach(
    waitForAsync(() => {
      TestBed.configureTestingModule({
        imports: [MatSidenavModule, MatDialogModule, NoopAnimationsModule, RouterTestingModule, BrowserAnimationsModule],
        declarations: [MasterDetailViewComponent, DetailViewComponent, ResizeHandleComponent],
        providers: [
          {
            provide: MatDialog,
            useClass: MatDialogMock,
          },
        ],
      }).compileComponents();
    })
  );

  beforeEach(() => {
    fixture = TestBed.createComponent(MasterDetailViewComponent);
    component = fixture.componentInstance;
    component.useDialog = true;
    fixture.detectChanges();

    modalWindowService = TestBed.inject(ModalWindowService);
    spyOpenDialog = jest.spyOn(modalWindowService, 'openDialogWithComponent');

    closed = false;
    component.closed.subscribe(() => (closed = true));
  });

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

  const pressEscapeOnDialog = function () {
    const matDialog: MatDialogMock = TestBed.inject(MatDialog) as any;
    const escapeKeydownEvent = new KeyboardEvent('keydown', { code: 'Escape' });
    matDialog.keydownEvents$.next(escapeKeydownEvent);

    fixture.detectChanges();
    tick(5000);
  };

  const pressEscapeOnSidebar = function () {
    const sidenavElement = fixture.debugElement.query(By.css('mat-sidenav'));
    sidenavElement.triggerEventHandler('keydown.escape', { code: 'Escape' });

    fixture.detectChanges();
    tick(5000);
  };

  const clickDialogBackdrop = function () {
    const matDialog: MatDialogMock = TestBed.inject(MatDialog) as any;
    const backdropClickEvent = new MouseEvent('click');
    matDialog.backdropClick$.next(backdropClickEvent);

    fixture.detectChanges();
    tick(5000);
  };

  const clickSidebarBackdrop = function () {
    const backdropElement = fixture.debugElement.query(By.css('.mat-drawer-backdrop'));
    backdropElement.nativeElement.click();

    fixture.detectChanges();
    tick(5000);
  };

  describe('with dialog', () => {
    beforeEach(fakeAsync(() => {
      // 'has modal window service'
      expect(modalWindowService).toBeTruthy();
      expect(spyOpenDialog).not.toHaveBeenCalled();
      // 'details not shown'
      expect(component.isDetailsShown).toBeFalsy();
      // 'not closed'
      expect(closed).toBeFalsy();

      component.openDetails();
      fixture.detectChanges();
      tick(5000);

      // 'details shown'
      expect(component.isDetailsShown).toBeTruthy();
      // 'not closed'
      expect(closed).toBeFalsy();
      expect(spyOpenDialog).toHaveBeenCalled();
    }));

    it('should open and close', fakeAsync(() => {
      component
        .closeDetails()
        .pipe(first())
        .subscribe(() => void 0);
      fixture.detectChanges();
      tick(5000);

      expect(component.isDetailsShown).toBeFalsy();
      expect(closed).toBeTruthy();
    }));

    it('should emit on closed-observable when calling close without subscribe', fakeAsync(() => {
      component.closeDetails();
      fixture.detectChanges();
      tick(5000);

      expect(closed).toBeTruthy();
    }));

    describe('with close on escape', () => {
      beforeEach(() => {
        component.closeOnEscape = true;
      });

      it('should close', fakeAsync(() => {
        pressEscapeOnDialog();

        // 'details closed'
        expect(component.isDetailsShown).toBeFalsy();
        // 'closed'
        expect(closed).toBeTruthy();
      }));
    });

    describe('without close on escape', () => {
      beforeEach(() => {
        component.closeOnEscape = false;
      });

      it('should not close', fakeAsync(() => {
        pressEscapeOnDialog();

        // 'details still shown'
        expect(component.isDetailsShown).toBeTruthy();
        // 'still not closed'
        expect(closed).toBeFalsy();
      }));
    });

    describe('with close on backdrop click', () => {
      beforeEach(() => {
        component.closeOnBackdropClick = true;
      });

      it('should close', fakeAsync(() => {
        clickDialogBackdrop();

        // 'details closed'
        expect(component.isDetailsShown).toBeFalsy();
        // 'closed'
        expect(closed).toBeTruthy();
      }));
    });

    describe('without close on backdrop click', () => {
      beforeEach(() => {
        component.closeOnBackdropClick = false;
      });

      it('should not close', fakeAsync(() => {
        clickDialogBackdrop();

        // 'details still shown'
        expect(component.isDetailsShown).toBeTruthy();
        // 'still not closed'
        expect(closed).toBeFalsy();
      }));
    });
  });

  describe('with sidebar', () => {
    beforeEach(fakeAsync(() => {
      // 'details not shown'
      expect(component.isDetailsShown).toBeFalsy();
      // 'not closed'
      expect(closed).toBeFalsy();

      component.useDialog = false;
      component.openDetails();
      fixture.detectChanges();
      tick(5000);

      // 'details shown'
      expect(component.isDetailsShown).toBeTruthy();
      // 'not closed'
      expect(closed).toBeFalsy();
    }));

    it('should open and close', fakeAsync(() => {
      component
        .closeDetails()
        .pipe(first())
        .subscribe(() => void 0);
      fixture.detectChanges();
      tick(5000);

      expect(component.isDetailsShown).toBeFalsy();
      expect(closed).toBeTruthy();
    }));

    it('should emit on closed-observable when calling close without subscribe', fakeAsync(() => {
      component.closeDetails();
      fixture.detectChanges();
      tick(5000);

      expect(component.isDetailsShown).toBeFalsy();
      expect(closed).toBeTruthy();
    }));

    describe('with close on escape', () => {
      beforeEach(() => {
        component.closeOnEscape = true;
      });

      it('should close', fakeAsync(() => {
        pressEscapeOnSidebar();

        // 'details closed'
        expect(component.isDetailsShown).toBeFalsy();
        // 'closed'
        expect(closed).toBeTruthy();
      }));
    });

    describe('without close on escape', () => {
      beforeEach(() => {
        component.closeOnEscape = false;
      });

      it('should not close', fakeAsync(() => {
        pressEscapeOnSidebar();

        // 'details still shown'
        expect(component.isDetailsShown).toBeTruthy();
        // 'still not closed'
        expect(closed).toBeFalsy();
      }));
    });

    describe('with close on backdrop click', () => {
      beforeEach(() => {
        component.closeOnBackdropClick = true;
      });

      it('should close', fakeAsync(() => {
        clickSidebarBackdrop();

        // 'details closed'
        expect(component.isDetailsShown).toBeFalsy();
        // 'closed'
        expect(closed).toBeTruthy();
      }));
    });

    describe('without close on backdrop click', () => {
      beforeEach(() => {
        component.closeOnBackdropClick = false;
      });

      it('should not close', fakeAsync(() => {
        clickSidebarBackdrop();

        // 'details still shown'
        expect(component.isDetailsShown).toBeTruthy();
        // 'still not closed'
        expect(closed).toBeFalsy();
      }));
    });
  });
});
