/* eslint-disable @typescript-eslint/no-non-null-assertion,@typescript-eslint/ban-ts-comment */
/*
 * Copyright (C) 2020 StApps
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */
import {
  APP_BASE_HREF,
  CommonModule,
  Location,
  LocationStrategy,
  PathLocationStrategy,
} from '@angular/common';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {FormsModule} from '@angular/forms';
import {
  ChildrenOutletContexts,
  RouterModule,
  UrlSerializer,
} from '@angular/router';
import {IonicModule} from '@ionic/angular';
import {TranslateModule} from '@ngx-translate/core';
import {SCFacet, SCThingType} from '@openstapps/core';
import {ContextMenuComponent} from './context-menu.component';
import {SettingsModule} from '../../settings/settings.module';
import {ContextMenuService} from './context-menu.service';
import {FilterContext, SortContext} from './context-type';

describe('ContextMenuComponent', async () => {
  let fixture: ComponentFixture<ContextMenuComponent>;
  let instance: ContextMenuComponent;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [ContextMenuComponent],
      providers: [
        ChildrenOutletContexts,
        Location,
        UrlSerializer,
        ContextMenuService,
        {provide: LocationStrategy, useClass: PathLocationStrategy},
        {provide: APP_BASE_HREF, useValue: '/'},
      ],
      imports: [
        FormsModule,
        IonicModule.forRoot(),
        TranslateModule.forRoot(),
        CommonModule,
        SettingsModule,
        RouterModule.forRoot([], {relativeLinkResolution: 'legacy'}),
      ],
    }).compileComponents();

    fixture = TestBed.createComponent(ContextMenuComponent);
    instance = fixture.componentInstance;
  });

  it('should show items in sort context', () => {
    instance.sortOption = getSortContextType();
    fixture.detectChanges();
    const sort: HTMLElement =
      fixture.debugElement.nativeElement.querySelector('.context-sort');
    const sortItem = sort.querySelector('.sort-item');
    expect(sortItem!.querySelector('ion-label')?.textContent).toContain(
      'relevance',
    );
  });

  it('should show items in filter context', () => {
    instance.filterOption = getFilterContextType();
    fixture.detectChanges();
    const filter: HTMLElement =
      fixture.debugElement.nativeElement.querySelector('.context-filter');
    const filterItem = filter.querySelector('.filter-group');
    expect(filterItem!.querySelector('ion-list-header')!.textContent).toContain(
      'Type',
    );
  });

  it('should set sort context value and reverse on click', () => {
    instance.sortOption = getSortContextType();
    fixture.detectChanges();
    const sort: HTMLElement =
      fixture.debugElement.nativeElement.querySelector('.context-sort');
    // @ts-ignore
    const sortItem: HTMLElement = sort.querySelectorAll('.sort-item')[1];
    sortItem!.click();
    expect(instance.sortOption.value).toEqual('name');
    expect(instance.sortOption.reversed).toBe(false);

    // click again for reverse
    sortItem!.click();
    expect(instance.sortOption.reversed).toBe(true);
  });

  it('should show all filterable facets', () => {
    // get set facets with non empty buckets
    const facets: SCFacet[] = getFilterContextType().options;

    instance.filterOption = getFilterContextType();
    fixture.detectChanges();
    // get filter context div
    const filter: HTMLElement =
      fixture.debugElement.nativeElement.querySelector('.context-filter');
    // get all filter groups that represent a facet
    const filterGroups = filter.querySelectorAll('.filter-group');

    expect(filterGroups.length).toEqual(facets.length);

    for (const facet of facets) {
      let filterGroup;

      // get filter option for facets field
      // eslint-disable-next-line unicorn/no-array-for-each
      filterGroups.forEach(element => {
        if (
          element
            .querySelector('ion-list-header')!
            .textContent!.toString()
            .toLowerCase()
            .includes(facet.field)
        ) {
          filterGroup = element;
          return;
        }
      });

      expect(filterGroup).toBeDefined();

      // @ts-ignore
      const filterItems = filterGroup.querySelectorAll('.filter-item-label');

      if (filterItems.length !== facet.buckets.length) {
        console.log(JSON.stringify(facet));
      }
      expect(filterItems.length).toEqual(facet.buckets.length);

      // check all buckets are shown
      for (const bucket of facet.buckets) {
        let filterItem;

        for (let i = 0; i < filterItems.length; i++) {
          if (
            filterItems
              .item(i)
              .textContent!.toString()
              .toLowerCase()
              .indexOf(bucket.key.toLowerCase()) > 0
          ) {
            filterItem = filterItems.item(i);
            break;
          }
        }
        expect(filterItem).toBeDefined();
      }
    }
  });

  it('should reset filter', () => {
    instance.filterOption = getFilterContextType();
    instance.filterOption.options = [
      {
        field: 'type',
        buckets: [{count: 10, key: 'date series', checked: true}],
      },
    ];

    fixture.detectChanges();

    // click reset button
    const resetButton: HTMLElement =
      fixture.debugElement.nativeElement.querySelector('.resetFilterButton');
    resetButton.click();

    expect(instance.filterOption.options[0].buckets[0].checked).toEqual(false);
  });
});

/**
 *
 */
function getSortContextType(): SortContext {
  return {
    name: 'sort',
    reversed: false,
    value: 'relevance',
    values: [
      {
        reversible: false,
        value: 'relevance',
      },
      {
        reversible: true,
        value: 'name',
      },
      {
        reversible: true,
        value: 'date',
      },
      {
        reversible: true,
        value: 'type',
      },
    ],
  };
}

/**
 *
 */
function getFilterContextType(): FilterContext {
  return {
    name: 'filter',
    compact: false,
    options: facetsMock
      .filter(facet => facet.buckets.length > 0)
      .map(facet => {
        return {
          buckets: facet.buckets.map(bucket => {
            return {
              count: bucket.count,
              key: bucket.key,
              checked: false,
            };
          }),
          compact: false,
          field: facet.field,
          onlyOnType: facet.onlyOnType,
        };
      }),
  };
}

const facetsMock: SCFacet[] = [
  {
    buckets: [
      {
        count: 60,
        key: 'academic event',
      },
      {
        count: 160,
        key: 'message',
      },
      {
        count: 151,
        key: 'date series',
      },
      {
        count: 106,
        key: 'dish',
      },
      {
        count: 20,
        key: 'building',
      },
    ],
    field: 'type',
  },
  {
    buckets: [
      {
        count: 12,
        key: 'Max Mustermann',
      },
      {
        count: 2,
        key: 'Foo Bar',
      },
    ],
    field: 'performers',
    onlyOnType: SCThingType.AcademicEvent,
  },
  {
    buckets: [
      {
        count: 5,
        key: 'colloquium',
      },
      {
        count: 15,
        key: 'course',
      },
    ],
    field: 'categories',
    onlyOnType: SCThingType.AcademicEvent,
  },
  {
    buckets: [
      {
        count: 5,
        key: 'employees',
      },
      {
        count: 15,
        key: 'students',
      },
    ],
    field: 'audiences',
    onlyOnType: SCThingType.Message,
  },
];
