import { computed, inject, Injectable, signal } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { delay, map, 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>

  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;
      })
    )
  }

  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);
  }

  refreshCommonData = signal<{ uid: string }>(null);
  commonDataRes = this.fastRes.http<CommonData>(() => {
    this.refreshCommonData();
    return { url: `${this.baseUrl}/GetCommonData` };
  })

  screenPaths = computed(() => {
    const commonDataVal = this.commonDataRes.value();
    if (!commonDataVal)
      return new Dictionary<string>();

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

  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' }
    };
  });
}
