import { Injectable, OnDestroy, signal } from '@angular/core';

const STORAGE_KEY = 'pmu_theme'; // 'light' | 'dark' | 'system'

type Mode = 'light' | 'dark' | 'system';

@Injectable({ providedIn: 'root' })
export class Theme implements OnDestroy {
  mode = signal<Mode>('light');

  private mql?: MediaQueryList;
  private onMqlChange = (e: MediaQueryListEvent) => {
    // only react if user selected "system"
    if (this.mode() === 'system') this.apply('system', /*fromMql*/ true);
  };

  constructor() {
    const saved = (localStorage.getItem(STORAGE_KEY) as Mode | null) ?? 'system';
    this.setupMql();
    this.apply(saved);
  }

  ngOnDestroy(): void {
    this.teardownMql();
  }

  toggle() {
    // If you're on "system", decide based on current resolved value
    const resolved = this.resolve(this.mode());
    const next: Mode = resolved === 'dark' ? 'light' : 'dark';
    this.apply(next);
  }

  /**
   * Optionally expose a 3-state cycle:
   * light -> dark -> system -> light ...
   */
  cycle() {
    const order: Mode[] = ['light', 'dark', 'system'];
    const i = order.indexOf(this.mode());
    this.apply(order[(i + 1) % order.length]);
  }

  apply(next: Mode, fromMql = false) {
    this.mode.set(next);
    const root = document.documentElement;
    const resolved = this.resolve(next);

    // toggle class
    root.classList.toggle('dark', resolved === 'dark');
    // attribute for any 3rd-party styling
    root.setAttribute('data-theme', resolved);

    // store only when user explicitly changed (avoid thrashing on mql change)
    if (!fromMql) localStorage.setItem(STORAGE_KEY, next);
  }

  private resolve(mode: Mode): 'light' | 'dark' {
    // SSR guard
    if (typeof window === 'undefined') return mode === 'dark' ? 'dark' : 'light';

    if (mode !== 'system') return mode;
    const prefersDark = this.mql?.matches ?? false;
    return prefersDark ? 'dark' : 'light';
  }

  private setupMql() {
    if (typeof window === 'undefined' || !window.matchMedia) return;
    this.mql = window.matchMedia('(prefers-color-scheme: dark)');

    // modern browsers
    if ('addEventListener' in this.mql) {
      this.mql.addEventListener('change', this.onMqlChange);
    } else {
      // Safari < 14 fallback
      // @ts-expect-error legacy
      this.mql.addListener(this.onMqlChange);
    }
  }

  private teardownMql() {
    if (!this.mql) return;
    if ('removeEventListener' in this.mql) {
      this.mql.removeEventListener('change', this.onMqlChange);
    } else {
      // @ts-expect-error legacy
      this.mql.removeListener(this.onMqlChange);
    }
  }
}
