import { Injectable, OnDestroy, signal } from '@angular/core';
import { Observable, fromEvent, Subject } from 'rxjs';
import { takeUntil, map, startWith, distinctUntilChanged } from 'rxjs/operators';

export interface AccessibilityPreferences {
  prefersReducedMotion: boolean;
  prefersHighContrast: boolean;
  prefersDarkMode: boolean;
  prefersReducedTransparency: boolean;
}

@Injectable({
  providedIn: 'root'
})
export class HighContrastService implements OnDestroy {
  private destroy$ = new Subject<void>();
  
  // Reactive signals for preferences
  readonly prefersReducedMotion = signal(false);
  readonly prefersHighContrast = signal(false);
  readonly prefersDarkMode = signal(false);
  readonly prefersReducedTransparency = signal(false);

  // Media query lists
  private reducedMotionQuery?: MediaQueryList;
  private highContrastQuery?: MediaQueryList;
  private darkModeQuery?: MediaQueryList;
  private reducedTransparencyQuery?: MediaQueryList;

  constructor() {
    this.setupMediaQueries();
    this.updatePreferences();
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }

  /**
   * Get all accessibility preferences as an observable
   */
  getPreferences$(): Observable<AccessibilityPreferences> {
    if (typeof window === 'undefined') {
      return new Observable(subscriber => {
        subscriber.next({
          prefersReducedMotion: false,
          prefersHighContrast: false,
          prefersDarkMode: false,
          prefersReducedTransparency: false
        });
      });
    }

    return fromEvent(window, 'change').pipe(
      takeUntil(this.destroy$),
      startWith(null),
      map(() => this.getCurrentPreferences()),
      distinctUntilChanged((prev, curr) => 
        prev.prefersReducedMotion === curr.prefersReducedMotion &&
        prev.prefersHighContrast === curr.prefersHighContrast &&
        prev.prefersDarkMode === curr.prefersDarkMode &&
        prev.prefersReducedTransparency === curr.prefersReducedTransparency
      )
    );
  }

  /**
   * Get current accessibility preferences
   */
  getCurrentPreferences(): AccessibilityPreferences {
    return {
      prefersReducedMotion: this.prefersReducedMotion(),
      prefersHighContrast: this.prefersHighContrast(),
      prefersDarkMode: this.prefersDarkMode(),
      prefersReducedTransparency: this.prefersReducedTransparency()
    };
  }

  /**
   * Apply CSS classes to document body based on preferences
   */
  applyPreferencesToBody(): void {
    if (typeof document === 'undefined') return;

    const body = document.body;
    
    // Remove existing classes
    body.classList.remove(
      'prefers-reduced-motion',
      'prefers-high-contrast',
      'prefers-dark-mode',
      'prefers-reduced-transparency'
    );

    // Add classes based on current preferences
    if (this.prefersReducedMotion()) {
      body.classList.add('prefers-reduced-motion');
    }
    
    if (this.prefersHighContrast()) {
      body.classList.add('prefers-high-contrast');
    }
    
    if (this.prefersDarkMode()) {
      body.classList.add('prefers-dark-mode');
    }
    
    if (this.prefersReducedTransparency()) {
      body.classList.add('prefers-reduced-transparency');
    }
  }

  /**
   * Get CSS custom properties for motion duration based on reduced motion preference
   */
  getMotionDuration(normalDuration: string, reducedDuration = '0.01s'): string {
    return this.prefersReducedMotion() ? reducedDuration : normalDuration;
  }

  /**
   * Get appropriate animation timing based on reduced motion preference
   */
  getAnimationConfig(normal: any, reduced: any = { duration: '0.01s', easing: 'linear' }): any {
    return this.prefersReducedMotion() ? reduced : normal;
  }

  /**
   * Check if user prefers reduced motion and return appropriate CSS
   */
  getReducedMotionCSS(): string {
    if (this.prefersReducedMotion()) {
      return `
        *, *::before, *::after {
          animation-duration: 0.01ms !important;
          animation-iteration-count: 1 !important;
          transition-duration: 0.01ms !important;
          scroll-behavior: auto !important;
        }
      `;
    }
    return '';
  }

  /**
   * Setup media query listeners
   */
  private setupMediaQueries(): void {
    if (typeof window === 'undefined') return;

    // Reduced motion
    this.reducedMotionQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
    this.reducedMotionQuery.addEventListener('change', () => {
      this.updatePreferences();
      this.applyPreferencesToBody();
    });

    // High contrast
    this.highContrastQuery = window.matchMedia('(prefers-contrast: high)');
    this.highContrastQuery.addEventListener('change', () => {
      this.updatePreferences();
      this.applyPreferencesToBody();
    });

    // Dark mode
    this.darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)');
    this.darkModeQuery.addEventListener('change', () => {
      this.updatePreferences();
      this.applyPreferencesToBody();
    });

    // Reduced transparency
    this.reducedTransparencyQuery = window.matchMedia('(prefers-reduced-transparency: reduce)');
    this.reducedTransparencyQuery.addEventListener('change', () => {
      this.updatePreferences();
      this.applyPreferencesToBody();
    });

    // Apply initial preferences
    this.applyPreferencesToBody();
  }

  /**
   * Update preference signals
   */
  private updatePreferences(): void {
    this.prefersReducedMotion.set(this.reducedMotionQuery?.matches ?? false);
    this.prefersHighContrast.set(this.highContrastQuery?.matches ?? false);
    this.prefersDarkMode.set(this.darkModeQuery?.matches ?? false);
    this.prefersReducedTransparency.set(this.reducedTransparencyQuery?.matches ?? false);
  }

  /**
   * Create a style element with reduced motion CSS
   */
  injectReducedMotionStyles(): void {
    if (typeof document === 'undefined') return;

    const existingStyle = document.getElementById('a11y-reduced-motion');
    if (existingStyle) return;

    const style = document.createElement('style');
    style.id = 'a11y-reduced-motion';
    style.textContent = `
      @media (prefers-reduced-motion: reduce) {
        *, *::before, *::after {
          animation-duration: 0.01ms !important;
          animation-iteration-count: 1 !important;
          transition-duration: 0.01ms !important;
          scroll-behavior: auto !important;
        }
      }
      
      @media (prefers-contrast: high) {
        * {
          text-shadow: none !important;
          box-shadow: none !important;
        }
      }
    `;
    
    document.head.appendChild(style);
  }
}