import { DOCUMENT } from '@angular/common';
import { Injectable, inject } from '@angular/core';
import { take } from 'rxjs/operators';
import { ConfigService } from '../../core/config/config.service';
import { ThemeConfig } from '../../shared/models/config';
import { mapThemeConfigToCssVariables } from '../mappers/theme-css-vars.mapper';

@Injectable({ providedIn: 'root' })
export class ThemeEngineService {
  private readonly document = inject(DOCUMENT);
  private readonly configService = inject(ConfigService);

  private systemDarkQuery?: MediaQueryList;
  private systemDarkListener?: (event: MediaQueryListEvent) => void;

  initialize(): void {
    this.configService.loadBootstrap().pipe(take(1)).subscribe({
      next: (bootstrap) => this.applyTheme(bootstrap.theme),
      error: () => {
        // Theme bootstrapping should not break app startup.
      }
    });
  }

  applyTheme(theme: ThemeConfig): void {
    this.teardownSystemModeListener();

    const effectiveMode = this.resolveEffectiveMode(theme.mode);
    this.render(theme, effectiveMode);

    if (theme.mode === 'system' && typeof window !== 'undefined' && window.matchMedia) {
      this.systemDarkQuery = window.matchMedia('(prefers-color-scheme: dark)');
      this.systemDarkListener = () => this.render(theme, this.resolveEffectiveMode('system'));
      this.systemDarkQuery.addEventListener('change', this.systemDarkListener);
    }
  }

  private render(theme: ThemeConfig, effectiveMode: 'light' | 'dark'): void {
    const variables = mapThemeConfigToCssVariables(theme, effectiveMode);
    const root = this.document.documentElement;

    for (const [name, value] of Object.entries(variables)) {
      root.style.setProperty(name, value);
    }

    root.setAttribute('data-theme-id', theme.themeId);
    root.setAttribute('data-theme-mode', effectiveMode);
    root.setAttribute('data-icon-set', theme.iconSet);
  }

  private resolveEffectiveMode(mode: ThemeConfig['mode']): 'light' | 'dark' {
    if (mode === 'dark') {
      return 'dark';
    }
    if (mode === 'light') {
      return 'light';
    }
    return typeof window !== 'undefined' && window.matchMedia?.('(prefers-color-scheme: dark)').matches
      ? 'dark'
      : 'light';
  }

  private teardownSystemModeListener(): void {
    if (this.systemDarkQuery && this.systemDarkListener) {
      this.systemDarkQuery.removeEventListener('change', this.systemDarkListener);
    }
    this.systemDarkQuery = undefined;
    this.systemDarkListener = undefined;
  }
}
