import {
  ChangeDetectionStrategy,
  Component,
  computed,
  input,
  ViewEncapsulation,
} from '@angular/core';
import { provideIcons } from '@ng-icons/core';
import { isaSortByUpMedium } from '@isa/icons';
import { IconButtonComponent } from '@isa/ui/buttons';
import { toObservable, toSignal } from '@angular/core/rxjs-interop';
import { debounceTime, fromEvent, switchMap } from 'rxjs';

@Component({
  selector: 'utils-scroll-top-button',
  imports: [IconButtonComponent],
  providers: [provideIcons({ isaSortByUpMedium })],
  template: `
    @if (display()) {
      <button
        uiIconButton
        aria-label="Scroll to top"
        type="button"
        color="tertiary"
        size="large"
        data-what="scroll-top-button"
        name="isaSortByUpMedium"
        (click)="scrollTop()"
      ></button>
    }
  `,
  host: {
    '[class]': '["utils-scroll-top-button"]',
  },
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ScrollTopButtonComponent {
  /** The scroll target, either `window` or a specific element. */
  target = input<Window | HTMLElement>(window);

  /** Whether the target is an `HTMLElement`. */
  isTargetElement = computed(() => this.target() instanceof HTMLElement);

  /** The scroll event signal. */
  scrollEvent = toSignal(
    toObservable(this.target).pipe(
      switchMap((target) => fromEvent(target, 'scroll').pipe(debounceTime(16))),
    ),
  );

  /** Whether to display the button. */
  display = computed(() => {
    this.scrollEvent();
    const target = this.target();

    if (target instanceof HTMLElement) {
      return target.scrollTop;
    }

    return target.scrollY;
  });

  /** Scrolls to the top of the page. */
  scrollTop() {
    const prefersReducedMotion = window.matchMedia(
      '(prefers-reduced-motion: reduce)',
    ).matches; // Anforderung im Ticket

    this.target().scrollTo({
      top: 0,
      behavior: prefersReducedMotion ? 'auto' : 'smooth',
    });
  }
}
