import { Spectator, createComponentFactory } from '@ngneat/spectator/jest';
import { CheckboxInputComponent } from './checkbox-input.component';
import {
  FilterInput,
  FilterService,
  CheckboxFilterInputOption,
} from '../../core';
import { CheckboxComponent } from '@isa/ui/input-controls';
import { CheckboxInputControlComponent } from './checkbox-input-control.component';
import { InputType } from '../../types';
import { signal } from '@angular/core';
import { MockComponent } from 'ng-mocks';
import { NgIcon } from '@ng-icons/core';
import { FormsModule } from '@angular/forms';

describe('CheckboxInputComponent', () => {
  let spectator: Spectator<CheckboxInputComponent>;
  let filterService: FilterService;

  const option: CheckboxFilterInputOption = {
    path: ['group', 'key', 'opt'],
    key: 'opt',
    label: 'Option',
    value: 'opt',
  };

  const mockInputsSignal = signal<FilterInput[]>([
    {
      group: 'group',
      key: 'key',
      type: InputType.Checkbox,
      target: 'filter' as const,
      options: [option],
      selected: [],
      label: 'label',
    },
  ]);

  const mockFilterService = {
    inputs: mockInputsSignal,
    setInputCheckboxOptionSelected: jest.fn(),
    toggleAllCheckboxOptions: jest.fn(),
  };

  const createComponent = createComponentFactory({
    component: CheckboxInputComponent,
    imports: [FormsModule],
    declarations: [
      MockComponent(CheckboxComponent),
      MockComponent(CheckboxInputControlComponent),
      MockComponent(NgIcon),
    ],
    providers: [{ provide: FilterService, useValue: mockFilterService }],
    detectChanges: false,
  });

  beforeEach(() => {
    // Reset the mock signal to its initial state
    mockInputsSignal.set([
      {
        group: 'group',
        key: 'key',
        type: InputType.Checkbox,
        target: 'filter' as const,
        options: [option],
        selected: [],
        label: 'label',
      },
    ]);

    spectator = createComponent({ props: { inputKey: 'key' } });
    filterService = spectator.inject(FilterService);
    jest.clearAllMocks();
  });

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

  it('should compute allChecked as false when nothing selected', () => {
    spectator.detectChanges();
    expect(spectator.component.allChecked()).toBe(false);
  });

  it('should call setInputCheckboxOptionSelected for each option on toggleSelection', () => {
    const group = 'group';
    const key = 'key';
    const options = [option];
    spectator.detectChanges();
    spectator.component.toggleSelection();
    expect(filterService.toggleAllCheckboxOptions).toHaveBeenCalledWith({
      group,
      groupKey: key,
      checkboxOptions: options,
      selected: true,
    });
  });

  it('should compute allChecked as true when all options are checked', () => {
    // Simulate all options checked
    mockInputsSignal.set([
      {
        group: 'group',
        key: 'key',
        type: InputType.Checkbox,
        target: 'filter' as const,
        options: [option],
        selected: ['opt'],
        label: 'label',
      },
    ]);
    spectator.detectChanges();
    expect(spectator.component.allChecked()).toBe(true);
  });

  describe('filter functionality', () => {
    it('should show filter control when there are more than 20 options', () => {
      const manyOptions = Array.from({ length: 25 }, (_, i) => ({
        path: ['group', 'key', `opt${i}`],
        key: `opt${i}`,
        label: `Option ${i}`,
        value: `opt${i}`,
      }));

      mockInputsSignal.set([
        {
          group: 'group',
          key: 'key',
          type: InputType.Checkbox,
          options: manyOptions,
          selected: [],
          label: 'label',
          target: 'input',
        },
      ]);
      spectator.detectChanges();
      expect(spectator.component.filterControlVisible()).toBe(true);
    });

    it('should not show filter control when there are 20 or fewer options', () => {
      spectator.detectChanges();
      expect(spectator.component.filterControlVisible()).toBe(false);
    });

    it('should generate correct filter placeholder', () => {
      spectator.detectChanges();
      expect(spectator.component.filterPlaceholder()).toBe('label suchen...');
    });

    it('should filter options based on search query', () => {
      const multipleOptions = [
        {
          path: ['group', 'key', 'apple'],
          key: 'apple',
          label: 'Apple',
          value: 'apple',
        },
        {
          path: ['group', 'key', 'banana'],
          key: 'banana',
          label: 'Banana',
          value: 'banana',
        },
        {
          path: ['group', 'key', 'cherry'],
          key: 'cherry',
          label: 'Cherry',
          value: 'cherry',
        },
      ];

      mockInputsSignal.set([
        {
          group: 'group',
          key: 'key',
          type: InputType.Checkbox,
          options: multipleOptions,
          selected: [],
          label: 'label',
          target: 'input',
        },
      ]);

      spectator.component.filterQuery.set('app');
      spectator.detectChanges();

      const filteredOptions = spectator.component.options();
      expect(filteredOptions).toHaveLength(1);
      expect(filteredOptions[0].label).toBe('Apple');
    });
  });
});
