import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
import { MockComponent } from 'ng-mocks';
import { ReturnSummaryComponent } from './return-summary.component';
import {
  ReturnProcess,
  ReturnProcessService,
  ReturnProcessStore,
} from '@isa/oms/data-access';
import { ReturnSummaryItemComponent } from './return-summary-item/return-summary-item.component';
import { ActivatedRoute, Router } from '@angular/router';

jest.mock('@isa/core/tabs', () => ({
  injectTabId: () => jest.fn(() => 1),
}));

const MOCK_RETURN_PROCESSES: ReturnProcess[] = [
  { id: 1, processId: 1, productCategory: 'Electronics' } as ReturnProcess,
  { id: 2, processId: 1, productCategory: 'Books' } as ReturnProcess,
  { id: 3, processId: 2, productCategory: 'Clothing' } as ReturnProcess,
  { id: 4, processId: 2, productCategory: 'Home Goods' } as ReturnProcess,
  { id: 5, processId: 3, productCategory: 'Electronics' } as ReturnProcess,
  { id: 6, processId: 3, productCategory: 'Toys' } as ReturnProcess,
  { id: 7, processId: 4, productCategory: 'Books' } as ReturnProcess,
  { id: 8, processId: 4, productCategory: 'Garden' } as ReturnProcess,
];

describe('ReturnSummaryComponent', () => {
  let spectator: Spectator<ReturnSummaryComponent>;
  // Use createComponentFactory for standalone components
  const createComponent = createComponentFactory({
    component: ReturnSummaryComponent,
    imports: [MockComponent(ReturnSummaryItemComponent)],
    mocks: [ReturnProcessStore, ReturnProcessService, ActivatedRoute, Router],
  });

  beforeEach(() => {
    // Arrange: Create the component instance before each test
    spectator = createComponent({
      providers: [
        {
          provide: ReturnProcessStore,
          useValue: {
            entities: jest.fn(() => MOCK_RETURN_PROCESSES),
          },
        },
      ],
    });
  });

  it('should create the component', () => {
    // Assert: Check if the component instance was created successfully
    expect(spectator.component).toBeTruthy();
  });

  it('should have a defined processId', () => {
    // Assert: Check if the processId is defined
    expect(spectator.component.processId()).toBeTruthy();
  });

  it('should have two return processes', () => {
    // Arrange:
    const mockReturnProcesses: ReturnProcess[] = [
      MOCK_RETURN_PROCESSES[0],
      MOCK_RETURN_PROCESSES[1],
    ];

    // Act: Set the returnProcesses to the mock data
    const returnProcesses = spectator.component.returnProcesses();

    // Assert: Check if the returnProcesses array has two items
    expect(returnProcesses.length).toBe(2);
    expect(returnProcesses).toEqual(mockReturnProcesses);
  });

  it('should render the return summary item component', () => {
    // Arrange:
    const mockReturnProcesses: ReturnProcess[] = [
      MOCK_RETURN_PROCESSES[0],
      MOCK_RETURN_PROCESSES[1],
    ];
    jest
      .spyOn(spectator.component, 'returnProcesses')
      .mockReturnValue(mockReturnProcesses);

    // Act: Trigger change detection
    spectator.detectChanges();

    // Assert: Check if the return summary item component is rendered
    const returnSummaryItems = spectator.queryAll(ReturnSummaryItemComponent);

    expect(returnSummaryItems.length).toBe(mockReturnProcesses.length);
  });

  it('should set the returnProcess input correctly', () => {
    // Arrange:
    const mockReturnProcesses: ReturnProcess[] = [
      MOCK_RETURN_PROCESSES[0],
      MOCK_RETURN_PROCESSES[1],
    ];
    jest
      .spyOn(spectator.component, 'returnProcesses')
      .mockReturnValue(mockReturnProcesses);

    // Act: Trigger change detection
    spectator.detectChanges();

    // Assert: Check if the returnProcess input is set correctly
    const returnSummaryItems = spectator.queryAll(ReturnSummaryItemComponent);
    expect(returnSummaryItems[0].returnProcess).toEqual(mockReturnProcesses[0]);
    expect(returnSummaryItems[1].returnProcess).toEqual(mockReturnProcesses[1]);
  });

  it('should have proper E2E testing attributes', () => {
    // Arrange
    const mockReturnProcesses: ReturnProcess[] = [
      MOCK_RETURN_PROCESSES[0], // id: 1, processId: 1, category: 'Electronics'
      MOCK_RETURN_PROCESSES[1], // id: 2, processId: 1, category: 'Books'
    ];

    jest
      .spyOn(spectator.component, 'returnProcesses')
      .mockReturnValue(mockReturnProcesses);

    // Act
    spectator.detectChanges(); // Trigger change detection to render the template

    // Assert
    // Check heading attributes
    const heading = spectator.query('[data-what="heading"]');
    expect(heading).toBeTruthy();
    expect(heading).toHaveAttribute('data-which', 'return-summary-title');

    // Check container attributes
    const container = spectator.query('[data-what="container"]');
    expect(container).toBeTruthy();
    expect(container).toHaveAttribute('data-which', 'return-items-list');

    // Check list item attributes
    const listItems = spectator.queryAll('oms-feature-return-summary-item');
    expect(listItems.length).toBe(mockReturnProcesses.length);

    // Check attributes for the first item
    expect(listItems[0]).toHaveAttribute('data-what', 'list-item');
    expect(listItems[0]).toHaveAttribute('data-which', 'return-process-item');
    expect(listItems[0]).toHaveAttribute(
      'data-item-id',
      `${mockReturnProcesses[0].id}`,
    );

    expect(listItems[0]).toHaveAttribute(
      'data-item-category',
      mockReturnProcesses[0].productCategory,
    );

    // Check attributes for the second item
    expect(listItems[1]).toHaveAttribute('data-what', 'list-item');
    expect(listItems[1]).toHaveAttribute('data-which', 'return-process-item');
    expect(listItems[1]).toHaveAttribute(
      'data-item-id',
      `${mockReturnProcesses[1].id}`,
    );
    expect(listItems[1]).toHaveAttribute(
      'data-item-category',
      `${mockReturnProcesses[1].productCategory}`,
    );
    expect(listItems[1]).toHaveAttribute(
      'data-item-category',
      mockReturnProcesses[1].productCategory,
    );

    // Check button attributes
    const button = spectator.query('[data-what="button"]');
    expect(button).toBeTruthy();
    expect(button).toHaveAttribute('data-which', 'return-and-print');
  });

  it('should call returnItemsAndPrintRecipt when button is clicked', () => {
    // Arrange: Spy on the returnItemsAndPrintRecipt method
    const returnItemsAndPrintReciptSpy = jest.spyOn(
      spectator.component,
      'returnItemsAndPrintRecipt',
    );

    // Act: Trigger button click
    spectator.click('[data-what="button"][data-which="return-and-print"]');

    // Assert: Check if the method was called
    expect(returnItemsAndPrintReciptSpy).toHaveBeenCalled();
  });
});
