import { ComponentFixture, TestBed } from '@angular/core/testing';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { OrderConfirmationHeaderComponent } from './order-confirmation-header.component';
import { Component, DebugElement, input, signal } from '@angular/core';
import { By } from '@angular/platform-browser';
import { CheckoutPrintFacade } from '@isa/checkout/data-access';
import { OrderConfiramtionStore } from '../reward-order-confirmation.store';
import { of } from 'rxjs';
import { Printer, PrintFn, PrintButtonComponent } from '@isa/common/print';

// Mock PrintButtonComponent to avoid HttpClient dependency
@Component({
  selector: 'common-print-button',
  template: '<button>Prämienbeleg drucken</button>',
  standalone: true,
})
class MockPrintButtonComponent {
  printerType = input.required<string>();
  printFn = input.required<PrintFn>();
  directPrint = input<boolean | undefined>();
}

describe('OrderConfirmationHeaderComponent', () => {
  let component: OrderConfirmationHeaderComponent;
  let fixture: ComponentFixture<OrderConfirmationHeaderComponent>;
  let mockCheckoutPrintFacade: {
    printOrderConfirmation: ReturnType<typeof vi.fn>;
  };
  let mockStore: { orderIds: ReturnType<typeof signal<number[] | undefined>> };

  beforeEach(async () => {
    // Arrange: Create mocks
    mockCheckoutPrintFacade = {
      printOrderConfirmation: vi.fn().mockReturnValue(of({ error: false })),
    };

    mockStore = {
      orderIds: signal<number[] | undefined>([1, 2, 3]),
    };

    await TestBed.configureTestingModule({
      imports: [OrderConfirmationHeaderComponent],
      providers: [
        { provide: CheckoutPrintFacade, useValue: mockCheckoutPrintFacade },
        { provide: OrderConfiramtionStore, useValue: mockStore },
      ],
    })
      .overrideComponent(OrderConfirmationHeaderComponent, {
        remove: { imports: [PrintButtonComponent] },
        add: { imports: [MockPrintButtonComponent] },
      })
      .compileComponents();

    fixture = TestBed.createComponent(OrderConfirmationHeaderComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

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

  it('should render the header text', () => {
    // Act
    const heading: DebugElement = fixture.debugElement.query(By.css('h1'));

    // Assert
    expect(heading).toBeTruthy();
    expect(heading.nativeElement.textContent.trim()).toBe(
      'Prämienausgabe abgeschlossen',
    );
  });

  it('should apply correct CSS classes to heading', () => {
    // Act
    const heading: DebugElement = fixture.debugElement.query(By.css('h1'));

    // Assert
    expect(
      heading.nativeElement.classList.contains('text-isa-neutral-900'),
    ).toBe(true);
    expect(
      heading.nativeElement.classList.contains('isa-text-subtitle-1-regular'),
    ).toBe(true);
  });

  it('should render print button component', () => {
    // Act
    const printButton = fixture.debugElement.query(
      By.css('common-print-button'),
    );

    // Assert
    expect(printButton).toBeTruthy();
  });

  it('should pass print button to template', () => {
    // Act
    const printButton = fixture.debugElement.query(
      By.css('common-print-button'),
    );

    // Assert
    expect(printButton).toBeTruthy();
    expect(printButton.nativeElement.textContent.trim()).toContain(
      'Prämienbeleg drucken',
    );
  });

  it('should expose orderIds from store', () => {
    // Assert
    expect(component.orderIds).toBeTruthy();
    expect(component.orderIds()).toEqual([1, 2, 3]);
  });

  it('should handle empty orderIds in printFn', async () => {
    // Arrange
    mockStore.orderIds.set(undefined);
    const mockPrinter: Printer = {
      key: 'printer-2',
      value: 'Test Printer 2',
      selected: false,
      enabled: true,
    };

    // Act
    const result = await component.printFn(mockPrinter);

    // Assert
    expect(mockCheckoutPrintFacade.printOrderConfirmation).toHaveBeenCalledWith(
      {
        printer: 'printer-2',
        data: [],
      },
    );
  });

  it('should use printer key from provided printer object', async () => {
    // Arrange
    const customPrinter: Printer = {
      key: 'custom-printer-key',
      value: 'Custom Printer Name',
      selected: true,
      enabled: true,
    };

    // Act
    await component.printFn(customPrinter);

    // Assert
    expect(mockCheckoutPrintFacade.printOrderConfirmation).toHaveBeenCalledWith(
      expect.objectContaining({
        printer: 'custom-printer-key',
      }),
    );
  });

  it('should pass current orderIds to printFn on each call', async () => {
    // Arrange
    const mockPrinter: Printer = {
      key: 'test-printer',
      value: 'Test Printer',
      selected: true,
      enabled: true,
    };

    // Act - First call with initial orderIds
    await component.printFn(mockPrinter);

    // Assert - First call
    expect(mockCheckoutPrintFacade.printOrderConfirmation).toHaveBeenCalledWith(
      {
        printer: 'test-printer',
        data: [1, 2, 3],
      },
    );

    // Arrange - Update orderIds
    mockStore.orderIds.set([4, 5]);

    // Act - Second call with updated orderIds
    await component.printFn(mockPrinter);

    // Assert - Second call should use updated orderIds
    expect(mockCheckoutPrintFacade.printOrderConfirmation).toHaveBeenCalledWith(
      {
        printer: 'test-printer',
        data: [4, 5],
      },
    );
  });
});
