import { PageLoadingService } from '../services/pageloading.service';
import { Globals, IAppPage } from './globals';
import { AppLogsService } from './applogs.service';
import { AuthorizeService } from './authorize.service';
import { CoreUser } from '../models/coreuser';
import { Router } from '@angular/router';
import { BaseEntity, BaseEntityCallBack, ErrorCallBack } from '../models/generics/baseentity';
import { BaseEntityListWrapper } from '../models/generics/baseentitylist.wrapper';
import { BehaviorSubject, Subscription } from 'rxjs';
import { HenselTranslateService } from './localization/hensel-translate.service';
import { inject } from '@angular/core';
import { BaseEntityWrapper } from '../models/generics/baseentity.wrapper';
import { MatDialogService } from './mat-dialog.service';
import { LocaleService } from './localization/locale.service';
import { RepositoryService } from './http/repository.service';

export class CorePageService {
  protected appPage: number;
  protected get applicationPage(): any {
    return this.appPage;
  }
  protected get appPageNoQueries(): number {
    return 0;
  }
  protected standAlone: boolean = true; //true = page data are not depended from the global data.service, and must be loaded explicetely

  protected loadImedeately: boolean = false; //load on opening the page
  protected entityList4Routing: BaseEntityListWrapper<BaseEntity>;
  public loadedOverRoutingCallBack: BaseEntityCallBack = null;
  public loadRoutingEntityCallBack: (entityId: number, _loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void) => void;
  public loadedOverRoutingOneTimeCallBack: BaseEntityCallBack = null;
  public lastURL: string;
  public pageBaseDateWereLoaded$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
  private _loadFromTheSamePage: boolean = false;
  public get loadFromTheSamePage(): boolean {
    return this._loadFromTheSamePage;
  }
  protected set loadFromTheSamePage(value: boolean) {
    this._loadFromTheSamePage = value;
  }
  private _isLoadingOverRouting: boolean = false;
  public get isLoadingOverRouting(): boolean {
    return this._isLoadingOverRouting;
  }
  protected set isLoadingOverRouting(value: boolean) {
    this._isLoadingOverRouting = value;
  }
  protected translationService = inject(HenselTranslateService);
  protected globalsService: Globals = inject(Globals);
  protected pageLoadingService: PageLoadingService = inject(PageLoadingService);
  protected appLogsService: AppLogsService = inject(AppLogsService);
  protected authService?: AuthorizeService = inject(AuthorizeService);
  protected router?: Router = inject(Router);
  protected dialog: MatDialogService = inject(MatDialogService);
  protected localeService: LocaleService = inject(LocaleService);
  protected repoService: RepositoryService = inject(RepositoryService);

  protected backgroundLoading: boolean = false; //no need background loading at first time

  protected baseEntityWrapperWaitLoadingSubscription: Subscription;
  public set baseEntityWrapperWaitLoading(pageDetails: BaseEntityWrapper<any>) {
    this.baseEntityWrapperWaitLoadingSubscription = pageDetails.entityIsLoading$.subscribe((isLoading: boolean) => {
      if (isLoading) this.pageLoadingService.showSpinner();
      else this.pageLoadingService.hideSpinner();
    });
  }


  protected isPageActive(): boolean {
    return this.globalsService.currentPage === this.globalsService.appPages[this.applicationPage].path;
  }

  constructor(
  ) {
    this.finalise = this.finalise.bind(this);
    this.pageLoadingService.pageActive$.subscribe((param?: string) => {
      if (this.isPageActive()) {
        setTimeout(() => this.onPageActivated(param));
      } else this.loadFromTheSamePage = false;
    });

    if (this.authService) {
      this.authService.loginLogout$.subscribe((user: CoreUser) => {
        setTimeout(() => this.onLoggedInOut(new CoreUser(user)), 0);  //wait till oncreate is finished
      });
    }
  }

  protected init(
  ) {
    this.lastURL = '/' + this.globalsService.appPages[this.applicationPage].path;

    if (//!this.globalsService.isTheMainPage() && !this.standAlone || // do not need, because if !this.standAlone, then forgroundLoading$ fires imedeately after create the service, because it is a behaviour
      //after creating loads data for not standalone page except main page - for it loading is calling after stammdata are loaded on forgroundLoading$ event
      this.loadImedeately && this.standAlone // or load data always the page is created and is standalone (depends from data another pages)
      || this.isPageActive() && this.globalsService.urlParam) //or not created page is opened with the id as url param
    {
      setTimeout(() => this.onPageActivated(this.isPageActive() ? this.globalsService.urlParam : null)); //must fire after init and onLoggedInOut
    }

    if (!this.standAlone) {
      this.pageLoadingService.forgroundLoading$.subscribe(() => { if (this.isPageActive()) this.loadData(); }); //load data if it is the current page
      //if page is loadImedeately - is loaded on activating - there is no sense to load it in bachground
      if (!this.loadImedeately) this.pageLoadingService.backgroundLoading$.subscribe(() => { if (!this.isPageActive()) this.loadData(); }); //load data in background if it is not the current page
    }
  }

  protected onPageActivated(param: string) {
    this.doRouting4Id(param);
  }


  private loadOnPageAcivated() {
    this.backgroundLoading = false; //no need background loading
    this.loadData();
  }


  protected finalise() {
    this.pageLoadingService.updatePageLoadedCounters(this.appPage);
  }


  protected doRouting4Id(paramId: string | number) {
    if (this.entityList4Routing) {
      if (!paramId /*|| Number.isNaN(Number(paramId)) || Number(paramId) === 0*/) { //without parameters
        if (this.loadImedeately && !this.loadFromTheSamePage) this.loadOnPageAcivated();
        else {
          if (!this.entityList4Routing.focusedItemId) {
            if (this.entityList4Routing.focusedEntityShadowed) {
              this.entityList4Routing.focusedEntityShadowed.clear();
              this.entityList4Routing.focusedEntityShadowed.entityIsLoading = false; // to fire loaded$ for empty lists
            }
          } else this.entityList4Routing.focusedRoutingCallBack(this.entityList4Routing.focusedItem);
        }
        this.loadFromTheSamePage = false;
      } else {
        if (!Number.isNaN(Number(paramId))
          && Number(paramId) !== 0
          && this.entityList4Routing.focusedEntityShadowed
          && this.entityList4Routing.focusedEntityShadowed.inViewMode
        ) { //load details entity from the url params
          let loadFn: (entityId: number, _loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void) => void;
          this.isLoadingOverRouting = true;

          if (this.loadRoutingEntityCallBack) {
            loadFn = this.loadRoutingEntityCallBack;
          } else loadFn = this.entityList4Routing.focusedEntityShadowed.load.bind(this.entityList4Routing.focusedEntityShadowed);

          loadFn(Number(paramId),
            (entity) => {
              if (!entity || !entity.entityId) {
                this.navigateLastURL();
              } else {
                this.lastURL = this.router?.url;
                if (this.loadedOverRoutingOneTimeCallBack) {
                  this.loadedOverRoutingOneTimeCallBack();
                  this.loadedOverRoutingOneTimeCallBack = null;
                } else {
                  if (this.loadedOverRoutingCallBack) this.loadedOverRoutingCallBack();
                }
              }
              this.isLoadingOverRouting = false;
            },
            () => {
              this.isLoadingOverRouting = false;
              this.navigateLastURL();
            },
            () => { //in the case of empty master list the wrapper is simple cleared and no loade  only completed dcallbak is called
              this.isLoadingOverRouting = false;
            }
          );
          this.loadFromTheSamePage = false;
        } else this.navigateLastURL();
      }
    } else {
      if (this.loadImedeately) this.loadOnPageAcivated();
    }
  }


  public navigateLastURL() {
    this.router.navigate([this.lastURL]);
  }


  public activateRouting4EntityList(entityList: BaseEntityListWrapper<BaseEntity>, loadedOverRoutingCallBack?: BaseEntityCallBack) {
    this.entityList4Routing = entityList;
    this.loadedOverRoutingCallBack = loadedOverRoutingCallBack;
    entityList.focusedRoutingCallBack = this.focusedRoutingCallBack.bind(this);
  }


  public focusedRoutingCallBack(focusedItem: BaseEntity | number) {
    if (!this.isPageActive()) return;
    const entityId: number = (typeof focusedItem === 'number') ? focusedItem : (focusedItem?.entityId || 0);
    const currentEntity = this.entityList4Routing.focusedEntityShadowed;
    if ((entityId > 0) && currentEntity && this.globalsService.urlParam === entityId.toString()) {
      if (currentEntity.inViewMode) {
        if (currentEntity.entityId === entityId) currentEntity.reload();
        else currentEntity.entityId = entityId;
      }
    } else {
      this.loadFromTheSamePage = true;
      const url = this.router.serializeUrl(this.router.createUrlTree([this.globalsService.appPages[this.applicationPage].path, entityId > 0 ? entityId : '']));
      if (this.router?.url + '/' !== url) {
        //don't override routing during loading of entity
        if (!this.isLoadingOverRouting) {
          this.lastURL = url;
          this.router.navigate([url]);
        }
      } else if (this.entityList4Routing?.focusedEntityShadowed) this.entityList4Routing.focusedEntityShadowed.entityIsLoading = false; // to fire loaded$ for empty lists
    }
  }


  protected onLoggedInOut(user: CoreUser) {
    if (!this.authService.isLoggedIn()) this.clearData(); //clears data only during logout - otherwise can id in url can be lost
  }


  public clearData() {
  }


  protected loadData(callback?: () => void) {
    const isActivePage = this.isPageActive();
    if (isActivePage || !this.pageLoadingService.spinnerVisible) {
      // if called from constructor or is standalone or loaded at first time - no background loading is needed
      const needBackgroungLoadingOfDependendPages = isActivePage && !this.standAlone && this.backgroundLoading; //&& this.pageLoadingService.noOfHttpQueries4Page[this.applicationPage] !== -1;
      this.backgroundLoading = !this.standAlone;
      this.pageLoadingService.startSpinner(needBackgroungLoadingOfDependendPages, callback);
    }
    this.pageLoadingService.noOfHttpQueries4Page[this.applicationPage] = this.appPageNoQueries; //means, that page service is iniatilised
    this.appLogsService.dlog('%c' + this.translationService.instant(this.globalsService.appPages[this.applicationPage].messageCaption) + ' data are loading', 'color:brown');
  }


  protected loadBaseData(pageNo: number, noOfQueries: number, callback?: () => void) {
    this.pageLoadingService.startSpinner(true, () => { if (callback) callback(); this.pageBaseDateWereLoaded$.next(true); });
    this.pageLoadingService.noOfHttpQueries4Page[pageNo] = noOfQueries;
    this.appLogsService.dlog(this.globalsService.currentPage + ': %cstammdata data are loading', 'color:brown');
  }

}
