import { inject, Injectable, signal } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { ServerSettings } from '../utils/authClass'
import { delay, map, shareReplay, switchMap, tap } from 'rxjs/operators';
import { BehaviorSubject, Observable, combineLatest, of } from 'rxjs';
import { Dictionary } from '../utils/dictionary';
import { FastResourceService } from './fast-resource.service';

export interface ScreenItem {
  id: number;
  name: string;
  keywords: string;
  path: string;
  isNewScreen: boolean;
  isVisible: boolean;
  userHasPermission: boolean;
}

export interface ModuleMenu {
  id: number;
  name: string;
  path?: string;
  isNew: boolean;
  children?: ModuleMenu[];
}

export interface UserInfo {
  id: number;
  displayName: string;
  legalName: string;
  title: string;
  email: string;
  theme: string;
}

export interface CommonData {
  homeUrl: string;
  userInfo: UserInfo;
  moduleMenus: ModuleMenu[];
  screenItems: ScreenItem[];
  favorites: ScreenItem[];
  hasAdmin: boolean;
}

export interface MouseOverArgs {
  isMouseOver: boolean;
  force: boolean;
}

@Injectable({ providedIn: 'root' })
export class CommonService {
  private readonly baseUrl = `${window.location.origin}/api/Common`;

  areFavoritesOpen$: BehaviorSubject<boolean>
  isMouseOverFavorites$: BehaviorSubject<MouseOverArgs>
  isMouseOverFavoritesResult$: Observable<boolean>
  isInitialLoad: boolean = true;
  areFavoritesOpenResult$: Observable<boolean>
  serverSettings$: Observable<ServerSettings>
  commonData$: Observable<CommonData>
  screenPaths$: Observable<Dictionary<string>>

  http = inject(HttpClient);
  fastRes = inject(FastResourceService);
  constructor() {
    this.areFavoritesOpen$ = new BehaviorSubject<boolean>(false);
    this.isMouseOverFavorites$ = new BehaviorSubject<MouseOverArgs>({ isMouseOver: false, force: false })

    this.isMouseOverFavoritesResult$ = this.isMouseOverFavorites$.pipe(
      switchMap(mouseOverArgs => {
        return mouseOverArgs.isMouseOver || mouseOverArgs.force ? of(mouseOverArgs.isMouseOver) : of(mouseOverArgs.isMouseOver).pipe(delay(500));
      }),
      tap(isMouseOver => {
        if (!isMouseOver)
          this.areFavoritesOpen$.next(false);
      })
    )

    this.areFavoritesOpenResult$ = combineLatest([this.areFavoritesOpen$, this.isMouseOverFavoritesResult$]).pipe(
      map(([areFavoritesOpen, isMouseOver]) => {
        return !isMouseOver ? false : areFavoritesOpen;
      })
    )

    this.serverSettings$ = this.http.get<ServerSettings>(`${this.baseUrl}/GetServerSettings`).pipe(
      shareReplay(1)
    );

    this.commonData$ = this.http.get<CommonData>(`${this.baseUrl}/GetCommonData`).pipe(
      shareReplay(1)
    );

    this.screenPaths$ = this.commonData$.pipe(
      map(data => {
        //fills the exported screenPaths$ observable for use in other components
        //mainly used to set frame-window component urls
        const screenPaths: Dictionary<string> = new Dictionary<string>();
        data.screenItems.forEach(s => {
          screenPaths.set(s.name.replace(' (HTML5)', ''), s.path);
        });
        return screenPaths;
      })
    )
  }

  saveFavorites(favorites: ScreenItem[]): Observable<unknown> {
    const url = `${this.baseUrl}/SaveFavorites`;
    return this.http.put(url, favorites);
  }

  addFavorite(windowUrl: string): Observable<ScreenItem> {
    const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
    const url = `${this.baseUrl}/AddFavorite`;
    windowUrl = JSON.stringify(windowUrl);
    return this.http.put<ScreenItem>(url, windowUrl, { headers });
  }

  setMouseOver(isMouseOver: boolean, force: boolean) {
    this.isMouseOverFavorites$.next({ isMouseOver: isMouseOver, force: force });
  }

  toggleFavorites() {
    this.areFavoritesOpen$.next(!this.areFavoritesOpen$.value);
  }

  getServerThemeName = signal(null);
  serverThemeNameRes = this.fastRes.httpText<'light' | 'dark'>(() => {
    this.getServerThemeName();
    return { url: `${this.baseUrl}/GetThemeName` };
  });

  saveThemeToServer = signal<{ uid: string, themeName: 'light' | 'dark' }>(null);
  saveThemeToServerRes = this.fastRes.http(() => {
    const themeName = this.saveThemeToServer()?.themeName;
    if (!themeName) return undefined;

    return {
      url: `${this.baseUrl}/SaveTheme`,
      method: 'PUT',
      body: JSON.stringify(themeName),
      headers: { 'Content-Type': 'application/json' }
    };
  });
}
