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

/* tslint:disable:no-magic-numbers */

import { TestBed } from '@angular/core/testing';
import { BciColumnBrowserModel, Column, ColumnItem } from './column-browser.model';
import { ColumnBrowserService } from './column-browser.service';

const data: BciColumnBrowserModel[] = [
  { label: 'dummy1', children: [], model: 'dummy1' },
  {
    label: 'dummy2',
    children: [
      { label: 'dummy21', children: [], model: 'dummy21' },
      {
        label: 'dummy22',
        children: [{ label: 'dummy221', children: [], model: 'dummy21' }],
        model: 'dummy22',
      },
    ],
    model: 'dummy2',
  },
  {
    label: 'dummy3',
    children: [{ label: 'dummy31', children: [], model: 'dummy31' }],
    model: 'dummy3',
  },
];

const source = [
  new Column('dummyTitle1', [
    new ColumnItem(data[0], undefined, data[0].label, false, true, false),
    new ColumnItem(data[1], undefined, data[1].label, false, true, true),
    new ColumnItem(data[2], undefined, data[2].label, false, true, true),
  ]),
  new Column('dummyTitle2', [
    new ColumnItem(data[1].children[0], undefined, data[1].children[0].label, false, false, false),
    new ColumnItem(data[1].children[1], undefined, data[1].children[1].label, false, false, true),
    new ColumnItem(data[2].children[0], undefined, data[2].children[0].label, false, false, false),
  ]),
  new Column('dummyTitle3', [
    new ColumnItem(
      data[1].children[1].children[0],
      undefined,
      data[1].children[1].children[0].label,
      false,
      false,
      false
    ),
  ]),
];

const headers = ['dummyTitle1', 'dummyTitle2', 'dummyTitle3'];

source[1].items[0].parentItem = source[0].items[1];
source[1].items[1].parentItem = source[0].items[1];
source[1].items[2].parentItem = source[0].items[2];
source[2].items[0].parentItem = source[1].items[1];

describe('ColumnBrowserService', () => {
  let service: ColumnBrowserService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [ColumnBrowserService],
    });
    service = TestBed.inject(ColumnBrowserService);
    jest.spyOn(service as any, 'prepareColumns');
  });

  beforeEach(() => {
    service.initColumns(data, headers, []);
  });

  it('initColumns', (done) => {
    expect(service['prepareColumns']).toHaveBeenCalled();
    service.columns.subscribe((value) => {
      expect(value).toEqual(source);
      done();
    });
  });

  [
    { description: 'level = 0', level: 2, result: 2 },
    { description: 'level > columns', level: 1, result: 1 },
    { description: 'level = columns', level: 0, result: 0 },
  ].forEach((config) => {
    it(`resetColumns - ${config.description}`, (done) => {
      service.resetColumns(config.level);
      service.columns.subscribe((value) => {
        expect(value.length).toEqual(config.result);
        done();
      });
    });
  });

  describe('updateColumns', () => {
    beforeEach(() => {
      jest.spyOn(service as any, 'markSelectedPath');
      jest.spyOn(service as any, 'prepareChildren');
    });
    [
      { description: 'on root level w/o children', column: source[0].items[0], level: 1 },
      { description: 'on root level with children', column: source[0].items[2], level: 1 },
      { description: 'on children level w/o children', column: source[1].items[2], level: 2 },
      { description: 'on children level with children', column: source[1].items[0], level: 2 },
    ].forEach((config) => {
      it(config.description, () => {
        service.updateColumns(config.column, config.level);
        expect(service['markSelectedPath']).toHaveBeenCalledWith(config.column, config.level);
        expect(service['prepareChildren']).toHaveBeenCalledWith(config.column, config.level, false);
      });
    });
  });

  it('clearColumnSelection', (done) => {
    source[0].items[0].selected = true;
    service.updateColumns(source[0].items[0], 0);
    service.clearColumnSelection(0);
    service.columns.subscribe((value) => {
      expect(value[0].items[0].selected).toBe(false);

      source[0].items[0].selected = false;
      done();
    });
  });

  it('deselectColumnItem', (done) => {
    source[0].items[1].selected = true;
    source[1].items[0].selected = true;

    service.updateColumns(source[0].items[1], 0);
    service.updateColumns(source[1].items[0], 1);

    service.deselectColumnItem(source[0].items[1], 0);

    service.columns.subscribe((value) => {
      expect(value[0].items[1].selected).toBe(false);
      expect(value[1].items[0].selected).toBe(false);

      source[0].items[1].selected = false;
      source[1].items[0].selected = false;
      done();
    });
  });

  it('updateHeaders', (done) => {
    const newHeaders = ['firstDummy', 'secondDummy', 'thirdDummy'];
    service.updateHeaders(newHeaders);
    service.columns.subscribe((value) => {
      expect(value[0].title).toBe(newHeaders[0]);
      expect(value[1].title).toBe(newHeaders[1]);
      expect(value[2].title).toBe(newHeaders[2]);
      done();
    });
  });

  [
    { description: 'node has no children', column: source[0].items[0], level: 0, target: [] },
    { description: 'node has children', column: source[0].items[2], level: 0, target: ['dummy31'] },
  ].forEach((config) => {
    it(`prepareChildren - ${config.description}`, (done) => {
      service['prepareChildren'](config.column, config.level);
      service.columns.subscribe((value) => {
        const visibleItems = value[1].items.filter((item) => item.visible).map((item) => item.label);
        expect(visibleItems).toEqual(config.target);
        done();
      });
    });
  });
});
