import { Component, ChangeDetectionStrategy, HostListener, OnInit, AfterContentInit, inject, signal, effect, ChangeDetectorRef } from '@angular/core';
import { handleKeys, selectInputTextOnClick } from './utils/util';
import { CommonService } from './services/common.service';
import { MessageService } from './services/message.service';
import { BehaviorSubject } from 'rxjs';
import { ActivatedRoute, RouterOutlet } from '@angular/router';
import { environment } from '../../environments/environment';
import { uid, icons } from '../_shared/utils/util';
import { KENDO_SVGICON } from '@progress/kendo-angular-icons';
import { AsyncPipe } from '@angular/common';
import { KENDO_DIALOG } from '@progress/kendo-angular-dialog';
import { KENDO_TOOLTIP } from '@progress/kendo-angular-tooltip';
import { FastTipDirective } from './elements/fast-tip.directive';
import { AuthService } from './services/auth.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [KENDO_DIALOG, KENDO_SVGICON, KENDO_TOOLTIP, RouterOutlet, AsyncPipe, FastTipDirective]
})
export class AppComponent implements OnInit, AfterContentInit {
  @HostListener('keydown', ['$event']) onKeyDown(e: KeyboardEvent) {
    handleKeys(e);
  }
  @HostListener('mousedown', ['$event']) onMouseDown(e: MouseEvent) {
    selectInputTextOnClick(e);
  }

  commonService = inject(CommonService);
  messageService = inject(MessageService);
  activatedRoute = inject(ActivatedRoute);
  private readonly authService = inject(AuthService);
  private readonly cdr = inject(ChangeDetectorRef);
  icons = icons;

  isDev: boolean = !environment.production;
  isRoot: boolean = window.location.hash.toLowerCase() === '#/root';

  //use ngAfterContentInit instead of ngAfterViewInit because ngAfterViewInit causes an "Expression has changed after it was checked" error
  ngAfterContentInit(): void {
    this.activatedRoute.queryParams.subscribe(x => {
      const isTopless = x['topless'] ? true : false;
      this.isToplessSubject.next(isTopless);
      this.cdr.detectChanges(); // Trigger CD as this update might not be detected
    });
  }

  isToplessSubject = new BehaviorSubject<boolean>(true);
  isTopless$ = this.isToplessSubject.asObservable();

  isDarkTheme = signal(false);

  constructor() {
    effect(() => {
      const serverThemeName = this.commonService.serverThemeNameRes.value();
      if (serverThemeName === undefined || this.commonService.serverThemeNameRes.isLoading())
        return;

      this.applyTheme(serverThemeName);
      this.cdr.detectChanges(); // Trigger CD as this effect runs outside Angular's direct detection cycle
    });

  }

  ngOnInit(): void {
    this.applyTheme('useExisting');
    this.authService.restoreSavedRoute();
  }

  applyTheme(themeNameToApply: 'useExisting' | 'light' | 'dark') {
    const darkThemeNames = ['dark', 't2', 't3'];
    const needsSaving = themeNameToApply !== 'useExisting';

    if (themeNameToApply === 'useExisting') {
      const storedThemeName = localStorage.getItem('theme');
      themeNameToApply = storedThemeName && darkThemeNames.includes(storedThemeName) ? 'dark' : 'light';
    } else
      localStorage.setItem('theme', themeNameToApply);

    const elem = document.body;

    const needsLightClass = themeNameToApply === 'light' && !elem.classList.contains('light');
    if (needsLightClass) {
      elem.classList.remove('scheme-dark', 'dark');
      elem.classList.add('light', 'scheme-light');
    }

    const needsDarkClass = themeNameToApply === 'dark' && !elem.classList.contains('dark');
    if (needsDarkClass) {
      elem.classList.remove('scheme-light', 'light');
      elem.classList.add('dark', 'scheme-dark');
    }

    this.isDarkTheme.set(themeNameToApply === 'dark'); //this is for the theme icon

    if (needsSaving)
      this.commonService.saveThemeToServer.set({ uid: uid(), themeName: themeNameToApply })
  }
}
