import { TestBed } from '@angular/core/testing';
import { ComponentFixture } from '@angular/core/testing';
import { ScrollTopButtonComponent } from './scroll-top-button.component';

describe('ScrollTopButtonComponent (happy path)', () => {
  let fixture: ComponentFixture<ScrollTopButtonComponent>;
  let component: ScrollTopButtonComponent;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [ScrollTopButtonComponent],
    }).compileComponents();

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

    // Polyfill / Reset matchMedia für jedes Test-Setup
    Object.defineProperty(window, 'matchMedia', {
      writable: true,
      value: jest.fn().mockImplementation((query: string) => ({
        matches: false, // Default: keine reduzierte Animation
        media: query,
        onchange: null,
        addListener: jest.fn(), // deprecated, aber Angular / libs könnten darauf zugreifen
        removeListener: jest.fn(),
        addEventListener: jest.fn(),
        removeEventListener: jest.fn(),
        dispatchEvent: jest.fn(),
      })),
    });
  });

  it('should create', () => {
    // Act
    fixture.detectChanges();

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

  it('should call scrollTo with smooth when prefers-reduced-motion is false', () => {
    // Arrange
    const targetEl = document.createElement('div');
    (targetEl as any).scrollTo = jest.fn();
    fixture.componentRef.setInput('target', targetEl);
    // matchMedia default (set in beforeEach) returns matches: false

    // Act
    component.scrollTop();

    // Assert
    expect((targetEl as any).scrollTo).toHaveBeenCalledWith({
      top: 0,
      behavior: 'smooth',
    });
  });

  it('should call scrollTo with auto when prefers-reduced-motion is true', () => {
    // Arrange
    (window.matchMedia as jest.Mock).mockImplementationOnce(
      (query: string) => ({
        matches: true, // reduzierte Bewegungen bevorzugt
        media: query,
        onchange: null,
        addListener: jest.fn(),
        removeListener: jest.fn(),
        addEventListener: jest.fn(),
        removeEventListener: jest.fn(),
        dispatchEvent: jest.fn(),
      }),
    );

    const targetEl = document.createElement('div');
    (targetEl as any).scrollTo = jest.fn();
    fixture.componentRef.setInput('target', targetEl);

    // Act
    component.scrollTop();

    // Assert
    expect((targetEl as any).scrollTo).toHaveBeenCalledWith({
      top: 0,
      behavior: 'auto',
    });
  });

  it('should render button when target element scrolled down', () => {
    // Arrange
    jest.useFakeTimers();
    const targetEl = document.createElement('div');
    (targetEl as any).scrollTo = jest.fn();
    targetEl.scrollTop = 150; // > 0 so truthy
    fixture.componentRef.setInput('target', targetEl);

    // Act
    fixture.detectChanges();
    targetEl.dispatchEvent(new Event('scroll'));
    jest.advanceTimersByTime(20); // allow debounceTime(10) to elapse
    fixture.detectChanges();

    // Assert
    const button = fixture.nativeElement.querySelector(
      '[data-what="scroll-top-button"]',
    );
    expect(button).not.toBeNull();
    jest.useRealTimers();
  });

  it('should not render button when target element at top (scrollTop = 0)', () => {
    // Arrange
    jest.useFakeTimers();
    const targetEl = document.createElement('div');
    (targetEl as any).scrollTo = jest.fn();
    targetEl.scrollTop = 0; // top position
    fixture.componentRef.setInput('target', targetEl);

    // Act
    fixture.detectChanges();
    targetEl.dispatchEvent(new Event('scroll'));
    jest.advanceTimersByTime(20);
    fixture.detectChanges();

    // Assert
    const button = fixture.nativeElement.querySelector(
      '[data-what="scroll-top-button"]',
    );
    expect(button).toBeNull();
    jest.useRealTimers();
  });
});
