/*
 * Copyright (C) 2025 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/>.
 */
/* eslint-disable @typescript-eslint/no-non-null-assertion,@typescript-eslint/no-explicit-any */
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {FormsModule} from '@angular/forms';
import {CommonModule} from '@angular/common';
import {TranslateModule} from '@ngx-translate/core';
import {IonicModule} from '@ionic/angular';
import {SCThingType} from '@openstapps/core';
import {ContextMenuModalComponent} from './context-menu-modal.component';
import {ContextMenuService} from './context-menu.service';
import {FilterContext, SortContext} from './context-type';
import {provideIonicAngular, ModalController} from '@ionic/angular/standalone';
import {BehaviorSubject, of} from 'rxjs';
import {addIcons} from 'ionicons';
import {swapVertical, trash, menu} from 'ionicons/icons';

describe('ContextMenuModalComponent', () => {
  let fixture: ComponentFixture<ContextMenuModalComponent>;
  let component: ContextMenuModalComponent;
  let modalControllerSpy: jasmine.SpyObj<ModalController>;
  let contextMenuServiceMock: Partial<ContextMenuService>;

  // Register used icons (suppress warnings)
  addIcons({
    delete: trash,
    sort: swapVertical,
    menu: menu,
  });

  beforeEach(async () => {
    modalControllerSpy = jasmine.createSpyObj<ModalController>('ModalController', ['dismiss']);

    contextMenuServiceMock = {
      filterOptions: new BehaviorSubject<FilterContext | undefined>(getFilterContextType()),
      sortOptions: new BehaviorSubject<SortContext | undefined>(getSortContextType()),
      filterContextChanged$: of(getFilterContextType()),
      sortContextChanged$: of(getSortContextType()),
      contextFilterChanged: jasmine.createSpy(),
      contextSortChanged: jasmine.createSpy(),
    };

    await TestBed.configureTestingModule({
      declarations: [ContextMenuModalComponent],
      imports: [CommonModule, FormsModule, TranslateModule.forRoot(), IonicModule.forRoot()],
      providers: [
        provideIonicAngular(),
        {
          provide: ModalController,
          useValue: modalControllerSpy,
        },
        {
          provide: ContextMenuService,
          useValue: contextMenuServiceMock,
        },
      ],
    }).compileComponents();

    fixture = TestBed.createComponent(ContextMenuModalComponent);
    component = fixture.componentInstance;

    component.contextMenuService = contextMenuServiceMock as ContextMenuService;
    component.translator = {
      translatedPropertyValue: () => 'translated',
    } as any;

    fixture.detectChanges();
  });

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

  it('should load initial sort and filter context', () => {
    expect(component.sortOption?.value).toBe('relevance');
    expect(component.filterOption?.options?.length).toBeGreaterThan(0);
  });

  it('should display sort items', () => {
    const sortItems = fixture.nativeElement.querySelectorAll('.sort-item');
    expect(sortItems.length).toBe(component.sortOption.values.length);
  });

  it('should update and reverse sort value on click', () => {
    const value = component.sortOption.values[1]; // "name", reversible
    component.sortChanged(component.sortOption, value);
    expect(component.sortOption.value).toBe('name');
    expect(component.sortOption.reversed).toBeFalse();

    component.sortChanged(component.sortOption, value);
    expect(component.sortOption.reversed).toBeTrue();
  });

  it('should call contextFilterChanged when filter is reset', () => {
    component.filterOption.options[0].buckets[0].checked = true;
    component.resetFilter(component.filterOption);
    const allUnchecked = component.filterOption.options.every(opt =>
      opt.buckets.every(bucket => !bucket.checked),
    );
    expect(allUnchecked).toBeTrue();
    expect(contextMenuServiceMock.contextFilterChanged).toHaveBeenCalled();
  });

  it('should dismiss the modal', () => {
    component.dismiss();
    expect(modalControllerSpy.dismiss).toHaveBeenCalled();
  });
});

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

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

const facetsMock = [
  {
    buckets: [
      {count: 10, key: 'lecture'},
      {count: 5, key: 'seminar'},
    ],
    field: 'type',
    onlyOnType: SCThingType.AcademicEvent,
  },
  {
    buckets: [{count: 7, key: 'research'}],
    field: 'categories',
    onlyOnType: SCThingType.AcademicEvent,
  },
];
