import { Component, HostListener, inject, OnInit } from '@angular/core';
import { ActivatedRoute, Router, RouterModule, RouterOutlet, RoutesRecognized } from '@angular/router';
import { MatModule } from '../dependencies/angularlib/mat.module';
import { Angularlib } from 'angularlib/angularlib.module';
import { BaseComponent, untilDestroy } from 'angularlib/base.component';
import { Subject, Subscription, filter, map, repeat, take, takeUntil, timer } from 'rxjs';
import { Title } from '@angular/platform-browser';
import { LoginService } from 'angularlib/login/login.service';
import { CommonModule, DatePipe } from '@angular/common';
import { ChangeLanguage } from 'angularlib/labels/label.actions';
import { ComponentService } from 'angularlib/component.service';
import { NotificationModule } from 'angularlib/notification/notification.module';
import { NOTIFICATION_STATE_TOKEN } from 'angularlib/notification/notification.state';
import { Notification } from 'angularlib/notification/notification.actions';
import { generateId } from 'angularlib/base.service';
import { Store } from '@ngxs/store';
import config from '../config/config.json';
import { UIAuthActions } from 'angularlib/login/state/login.actions';
import { Platform } from '@angular/cdk/platform';
import { AppSettingsAction } from 'angularlib/ui.state/ui.state.actions';
import { PushNotificationDecorator as LeavePushNotif } from 'fis/leave/decorators/push.notification.decorator';
import { FISMessaging } from 'fis/index';
import { BusinessDataModule } from 'fis/business.data/business.data.module';
import { NotificationService } from 'angularlib/notification/notification.service';
import { env } from 'angularlib/environments/environment';
import { TranslatePipe } from 'angularlib/labels/translate.pipe';
import { ChatComponent } from 'angularlib/chat/chat.component';
import { HttpClient } from '@angular/common/http';

@Component({
    selector: 'app-root',
    imports: [
        CommonModule,
        RouterOutlet,
        MatModule,
        RouterModule,
        Angularlib,
        NotificationModule,
        BusinessDataModule,
        ChatComponent
    ],
    providers: [DatePipe, FISMessaging],
    templateUrl: './app.component.html',
    styleUrls: [
        './app.component.scss'
    ]
})
export class AppComponent extends BaseComponent implements OnInit {
  title = 'Financial Information System';

  /**current date */
  protected currentDate = new Date();

  /**session timeout duration in milliseconds*/
  private duration: number = config?.sessionTimeoutDuration;
  private startTimeout$ = new Subject();
  private stopTimeout$ = new Subject();
  private timeout = timer(this.duration).pipe(
      map(() => {
        if(this.loginService.user){
          console.warn('session inactive timeout, logging out...');
          this.store.dispatch(new UIAuthActions.RedirectAfterLogin(this.route.snapshot));
          this.loginService.logout();
        }
      }),
      takeUntil(this.stopTimeout$),
      repeat({delay:() => this.startTimeout$})
  );

  /**current theme of application */
  protected theme;

  /**number of notifications */
  protected notificationCount: number = 0;

  private leavePushNotif$: Subscription;

  private messaging = inject(FISMessaging);
  private notification = inject(NotificationService);
  private tr = inject(TranslatePipe);

  protected sampleMap = {
    hidden:true,
    markers: [
      {position:{lat:1.55176,lng:110.33429},title:'Software Optima'}
    ],
    polygons: [
      {paths: [{lat:1.551703,lng:110.334149},{lat:1.551703,lng:110.334409},{lat:1.55222,lng:110.33444},{lat:1.552223,lng:110.33417}],fillColor: "blue",strokeColor:'navy'},
      {paths: [{lat:1.55222,lng:110.33413},{lat:1.55224,lng:110.33375},{lat:1.551432,lng:110.333715},{lat:1.551404,lng:110.334387},{lat:1.551685,lng:110.334395},{lat:1.551704,lng:110.334100}],fillColor: "red",strokeColor:'red'}
    ]
  };

  private http = inject(HttpClient);

  constructor(
    private router: Router,
    private store: Store,
    protected loginService: LoginService,
    /**Platform Browser title */
    protected pbTitle: Title,
    protected cs: ComponentService,
    private route: ActivatedRoute,
    private platform: Platform
  ) {
    super(store,cs);
  }

  @HostListener('window:mousedown')
  refreshTimeout() {
    this.stopTimeout$.next(null);
    this.startTimeout$.next(null);
  }

  ngOnInit(): void {
    // check if site is under maintenance
    this.http.get('./config/config.json').pipe(take(1)).subscribe({
      next: (cfg:any) => {
        if (cfg?.maintenance?.active) {
          this.cs.dialog.showWarningDialog({
            title: 'Site Under Maintenance',
            content: `FIS is currently under maintenance.<br/>This maintenance is expected to continue until ${cfg?.maintenance?.endDatetime}.<br/>Sorry for any inconvenience caused.`,
            disableClose: true,
            hideCloseButton: true
          });
        }
      }
    });

    this.router.events.pipe(untilDestroy(this),
    filter((event) => event instanceof RoutesRecognized),
    map((res:any) => {
      const data = res.state.root.firstChild.firstChild || res.state.root.firstChild;
      return data.data?.title;
    })
    ).subscribe(title => {
      if (typeof title === 'string')
        this.title = title;
      else this.title = this.getLabel(title?.key,title?.default);
      if (env !== 'PROD') this.title += ` (${this.tr.transform('test','Test')})`;
      this.pbTitle.setTitle(this.title);
    });

    

    this.store.select(NOTIFICATION_STATE_TOKEN).pipe(untilDestroy(this)).subscribe({
      next: (state:any) => {
        this.notificationCount = state.notifications.length;
      }
    });

    

    if (this.platform.ANDROID || this.platform.IOS) this.pwaPrompt();
  }

  ngAfterViewInit() {
    /**subsribe user changes and initiate timeout timer */
    this.loginService.user$.pipe(untilDestroy(this)).subscribe((user:any) => {
      if (user) this.timeout.pipe(untilDestroy(this),takeUntil(this.loginService.loggedOut)).subscribe();
      this.subscribePushNotifications();
    });
    if (this.cs.isMobileClient) this.mobile.init();
  }

  /**
   * change application language
   * @param {string} language
   */
  protected changeLanguage(language: string) {
    this.store.dispatch(new ChangeLanguage(language));
    if (language.startsWith('en')) this.store.dispatch(new AppSettingsAction.SetLocale('en-MY'));
    if (language.startsWith('zh')) this.store.dispatch(new AppSettingsAction.SetLocale('zh-CN'));
    if (language.startsWith('ms')) this.store.dispatch(new AppSettingsAction.SetLocale('ms-MY'));
  }

  protected addNotification() {
    this.store.dispatch(new Notification.Add({
      message:{title:generateId(),desc:generateId(),timestamp: new Date()}
    }));
  }

  /**prompt to install PWA App */
  private pwaPrompt() {
    let installPrompt = null;
    const installButton = document.querySelector("#installApp");

    const disableInAppInstallPrompt = () =>  {
      installPrompt = null;
      installButton.setAttribute("hidden","");
    }

    window.addEventListener("beforeinstallprompt",(event) => {
      event.preventDefault();
      installPrompt = event;
      installButton.removeAttribute("hidden");
    });

    installButton.addEventListener("click", async () => {
      if (!installPrompt) return;
      const result = await installPrompt.prompt();
      disableInAppInstallPrompt();
    });

    window.addEventListener("appinstalled", () => {
      disableInAppInstallPrompt();
    });
  }

  private subscribePushNotifications() {
    if (this.loginService.user?.fisInfo) {
      if (this.leavePushNotif$ === undefined) {
        this.leavePushNotif$ = new LeavePushNotif(
          this,
          this.loginService,
          this.messaging,
          this.notification
        ).subscribe();
      }
    } else {
      if (this.leavePushNotif$) this.leavePushNotif$.unsubscribe();
      this.leavePushNotif$ = undefined;
    }
  }

  /**mobile controls */
  protected mobile = {
    /**init mobile controls */
    init: () => {
      const chatButton = document.getElementById('chat-toggle-button') as HTMLElement;
      if (chatButton) chatButton.style.display = 'none';
    },
    /**toggle chat window */
    toggleChat: () => {
      const chat = document.getElementById('chat-panel') as HTMLElement;
      if (chat) chat.style.display = chat.style.display === 'none' ? 'flex' : 'none';
    }
  }
}
