import { OverlayContainer } from '@angular/cdk/overlay';
import { Component, DebugElement } from '@angular/core';
import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, flushMicrotasks, inject, TestBed, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations';
import { BixiTableModule, EColType, ICols } from '@bixi/core/table';
import { BixiTableColOperationsComponent } from './col-operations.component';
import { dispatchFakeEvent, dispatchMouseEvent } from '@bixi/testing';
import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
import { NzProgressModule } from 'ng-zorro-antd/progress';

describe('col operations', () => {
  let fixture: ComponentFixture<TestComponent>;
  let context: TestComponent;
  let debugEle: DebugElement;
  let overlayContainerEle: HTMLElement;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [BixiTableModule, NzProgressModule, BrowserAnimationsModule, NzDropDownModule, NoopAnimationsModule],
      declarations: [TestComponent]
    });

    fixture = TestBed.createComponent(TestComponent);
    context = fixture.componentInstance;
    debugEle = fixture.debugElement;
  });

  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {
    overlayContainerEle = oc.getContainerElement();
  }));

  it('should init', () => {
    // given
    context.cols = [
      {
        name: '操作',
        key: 'opt',
        type: EColType.operations,
        operations: () => {
          return [
            {
              name: '查看'
            }
          ];
        }
      }
    ];

    // when
    fixture.detectChanges();

    // then
    expect(debugEle.query(By.directive(BixiTableColOperationsComponent))).toBeTruthy();
  });

  it('should basic operation work', () => {
    // given
    context.cols = [
      {
        name: '操作',
        key: 'opt',
        type: EColType.operations,
        operations: () => {
          return [
            {
              name: '查看'
            }
          ];
        }
      }
    ];

    // when
    fixture.detectChanges();

    // then
    const content = debugEle.query(By.directive(BixiTableColOperationsComponent)).query(By.css('.bixi-col-operation')).nativeElement
      .textContent;
    expect(content).toContain('查看');
  });

  it('should visible work', () => {
    // given
    context.cols = [
      {
        name: '操作',
        key: 'opt',
        type: EColType.operations,
        operations: () => {
          return [
            {
              name: '查看',
              visible: false
            }
          ];
        }
      }
    ];

    // when
    fixture.detectChanges();

    // then
    const content = debugEle.query(By.directive(BixiTableColOperationsComponent)).query(By.css('.bixi-col-operation'));
    expect(content).not.toBeTruthy();
  });

  it('should disabled work', () => {
    // given
    context.cols = [
      {
        name: '操作',
        key: 'opt',
        type: EColType.operations,
        operations: () => {
          return [
            {
              name: '查看',
              disabled: () => {
                return true;
              }
            }
          ];
        }
      }
    ];

    // when
    fixture.detectChanges();

    // then
    const content = debugEle.query(By.directive(BixiTableColOperationsComponent)).query(By.css('.bixi-col-operation'))
      .nativeElement as HTMLAnchorElement;
    expect(content.classList.contains('bixi-col-operation-disabled')).toBeTrue();
  });

  it('should click event work', () => {
    // given
    context.cols = [
      {
        name: '操作',
        key: 'opt',
        type: EColType.operations,
        operations: () => {
          return [
            {
              name: '查看',
              onClick: (row, index) => {
                context.text = `${row.name}_${index}`;
              }
            }
          ];
        }
      }
    ];

    // when
    fixture.detectChanges();
    const triggerEle = debugEle.query(By.directive(BixiTableColOperationsComponent)).query(By.css('.bixi-col-operation')).nativeElement;
    const testEle = debugEle.query(By.css('.test-text')).nativeElement;
    triggerEle.click();
    fixture.detectChanges();

    // then
    expect(testEle.textContent).toContain('阿明_0');
  });

  it('should sub operations work', fakeAsync(() => {
    // given
    context.cols = [
      {
        name: '操作',
        key: 'opt',
        type: EColType.operations,
        operations: () => {
          return [
            {
              name: '查看',
              children: [
                {
                  name: '查看_1'
                },
                {
                  name: '查看_2'
                }
              ]
            }
          ];
        }
      }
    ];

    // when
    fixture.detectChanges();
    const triggerEl = debugEle.query(By.directive(BixiTableColOperationsComponent)).query(By.css('.bixi-col-operation')).nativeElement;
    dispatchMouseEvent(triggerEl, 'mouseenter');
    waitingForOverlayVisible();

    // then
    expect(overlayContainerEle.textContent).toContain('查看_1');
    expect(overlayContainerEle.textContent).toContain('查看_2');
  }));

  it('should sub operations disabled work', fakeAsync(() => {
    // given
    const disabledCallback = jasmine.createSpy('disabledCallback');
    const normalCallback = jasmine.createSpy('normalCallback');
    context.cols = [
      {
        name: 'operations',
        key: 'opt',
        type: EColType.operations,
        operations: () => [
          {
            name: 'view',
            children: [
              {
                name: 'view_1',
                disabled: true,
                onClick: disabledCallback
              },
              {
                name: 'view_2',
                onClick: normalCallback
              }
            ]
          }
        ]
      }
    ];

    // when
    fixture.detectChanges();
    const triggerEl = debugEle.query(By.directive(BixiTableColOperationsComponent)).query(By.css('.bixi-col-operation')).nativeElement;
    dispatchMouseEvent(triggerEl, 'mouseenter');
    waitingForOverlayVisible();
    const disabledOperation = overlayContainerEle.querySelectorAll('li')[0] as HTMLLIElement;
    const normalOperation = overlayContainerEle.querySelectorAll('li')[1] as HTMLLIElement;
    disabledOperation.click();
    normalOperation.click();

    // then
    expect(disabledCallback).toHaveBeenCalledTimes(0);
    expect(normalCallback).toHaveBeenCalledTimes(1);
    flush();
    flushMicrotasks();
    discardPeriodicTasks();
  }));

  it('should sub operations tooltip work', fakeAsync(() => {
    // given
    context.cols = [
      {
        name: 'operations',
        key: 'opt',
        type: EColType.operations,
        operations: () => [
          {
            name: 'view',
            children: [
              {
                name: 'view_1',
                disabled: true,
                tooltip: 'tooltip_1'
              },
              {
                name: 'view_2',
                tooltip: 'tooltip_2'
              }
            ]
          }
        ]
      }
    ];

    // when
    fixture.detectChanges();
    const triggerEl = debugEle.query(By.directive(BixiTableColOperationsComponent)).query(By.css('.bixi-col-operation')).nativeElement;
    dispatchMouseEvent(triggerEl, 'mouseenter');
    waitingForOverlayVisible();
    const disabledOperation = overlayContainerEle.querySelectorAll('li')[0] as HTMLLIElement;
    const normalOperation = overlayContainerEle.querySelectorAll('li')[1] as HTMLLIElement;
    dispatchFakeEvent(disabledOperation, 'mouseenter');
    waitingForOverlayVisible();

    // then
    expect(overlayContainerEle.innerHTML).toContain('tooltip_1');

    // when
    dispatchFakeEvent(normalOperation, 'mouseenter');

    // then
    expect(overlayContainerEle.innerHTML).toContain('tooltip_2');
    flush();
    flushMicrotasks();
    discardPeriodicTasks();
  }));

  function waitingForOverlayVisible() {
    fixture.detectChanges();
    tick(500);
    fixture.detectChanges();
  }
});

const rows = [
  {
    name: '阿明',
    online: false
  }
];

@Component({
  template: `
    <span class="test-text">{{ text }}</span>
    <bixi-table [rows]="rows" [cols]="cols"></bixi-table>
  `
})
class TestComponent {
  text = '';
  rows = rows;
  cols: ICols = [];
}
