import {
  DestroyRef,
  Injectable,
  NgZone,
  computed,
  inject,
  signal
} from '@angular/core';

/**
 * Tracks viewport-level UX traits used to switch between desktop and mobile layouts.
 *
 * `isMobile` follows the Tailwind `md` breakpoint (max-width: 767.98px). It is the
 * single source of truth for whether the UI should render in mobile mode - components
 * and templates should use this signal rather than ad-hoc `window.innerWidth` checks.
 *
 * `isTouch` is a best-effort hint indicating coarse pointer / touch capability. It is
 * stable for the lifetime of the page and does not flip when devices are connected.
 */
@Injectable({ providedIn: 'root' })
export class ViewportService {
  /** Pixel breakpoint that separates mobile from tablet/desktop layouts. Matches Tailwind `md`. */
  static readonly MOBILE_MAX_WIDTH = 767.98;

  /** True when the viewport is in mobile mode (width <= MOBILE_MAX_WIDTH). */
  readonly isMobile = computed(() => this.isMobileSignal());
  /** True when the primary pointer is coarse (touch screen). */
  readonly isTouch = computed(() => this.isTouchSignal());
  /** Convenience: true when running on a non-mobile viewport. */
  readonly isDesktop = computed(() => !this.isMobileSignal());

  private readonly zone = inject(NgZone);
  private readonly destroyRef = inject(DestroyRef);

  private readonly mobileQuery: MediaQueryList | null;
  private readonly touchQuery: MediaQueryList | null;

  private readonly isMobileSignal = signal(false);
  private readonly isTouchSignal = signal(false);

  constructor() {
    if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
      this.mobileQuery = null;
      this.touchQuery = null;
      return;
    }

    this.mobileQuery = window.matchMedia(`(max-width: ${ViewportService.MOBILE_MAX_WIDTH}px)`);
    this.touchQuery = window.matchMedia('(pointer: coarse)');

    this.isMobileSignal.set(this.mobileQuery.matches);
    this.isTouchSignal.set(this.touchQuery.matches);

    const onMobileChange = (event: MediaQueryListEvent) => {
      this.zone.run(() => this.isMobileSignal.set(event.matches));
    };
    const onTouchChange = (event: MediaQueryListEvent) => {
      this.zone.run(() => this.isTouchSignal.set(event.matches));
    };

    this.mobileQuery.addEventListener('change', onMobileChange);
    this.touchQuery.addEventListener('change', onTouchChange);

    this.destroyRef.onDestroy(() => {
      this.mobileQuery?.removeEventListener('change', onMobileChange);
      this.touchQuery?.removeEventListener('change', onTouchChange);
    });
  }
}
