
import {
  Component,
  effect,
  HostListener,
  inject,
  Inject,
  Injector,
  OnInit,
  Renderer2,
  signal,
  untracked,
  DOCUMENT
} from '@angular/core';
import { Title } from '@angular/platform-browser';
import { SwUpdate } from '@angular/service-worker';
import { ApplicationService } from '@core/application';
import { Config } from '@core/config';
import { NotificationsHub } from '@hub/notifications';
import packageInfo from 'packageJson';
import { asapScheduler, interval, Subscription } from 'rxjs';
import { UserStateService } from '@generated/swagger/isa-api';
import { IsaLogProvider } from './providers';
import { EnvironmentService } from '@core/environment';
import { AuthService, LoginStrategy } from '@core/auth';
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
import { injectOnline$ } from './services/network-status.service';
import { toSignal } from '@angular/core/rxjs-interop';
import { animate, style, transition, trigger } from '@angular/animations';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  animations: [
    trigger('fadeInOut', [
      transition(':enter', [
        // :enter wird ausgelöst, wenn das Element zum DOM hinzugefügt wird
        style({ opacity: 0, transform: 'translateY(-100%)' }),
        animate('300ms', style({ opacity: 1, transform: 'translateY(0)' })),
      ]),
      transition(':leave', [
        // :leave wird ausgelöst, wenn das Element aus dem DOM entfernt wird
        animate('300ms', style({ opacity: 0, transform: 'translateY(-100%)' })),
      ]),
    ]),
  ],
  standalone: false,
})
export class AppComponent implements OnInit {
  readonly injector = inject(Injector);

  $online = toSignal(injectOnline$());

  $offlineBannerVisible = signal(false);

  $onlineBannerVisible = signal(false);

  private onlineBannerDismissTimeout: any;

  onlineEffects = effect(() => {
    const online = this.$online();
    const offlineBannerVisible = this.$offlineBannerVisible();

    untracked(() => {
      this.$offlineBannerVisible.set(!online);

      if (!online) {
        this.$onlineBannerVisible.set(false);
        clearTimeout(this.onlineBannerDismissTimeout);
      }

      if (offlineBannerVisible && online) {
        this.$onlineBannerVisible.set(true);
        this.onlineBannerDismissTimeout = setTimeout(() => this.$onlineBannerVisible.set(false), 5000);
      }
    });
  });

  private _checkForUpdates: number = this._config.get('checkForUpdates');

  get checkForUpdates(): number {
    return this._checkForUpdates ?? 60 * 60 * 1000; // default 1 hour
  }

  // For Unit Testing
  set checkForUpdates(time: number) {
    this._checkForUpdates = time;
  }

  subscriptions = new Subscription();

  constructor(
    private readonly _config: Config,
    private readonly _title: Title,
    private readonly _appService: ApplicationService,
    @Inject(DOCUMENT) private readonly _document: Document,
    private readonly _renderer: Renderer2,
    private readonly _swUpdate: SwUpdate,
    private readonly _notifications: NotificationsHub,
    private infoService: UserStateService,
    private readonly _environment: EnvironmentService,
    private readonly _authService: AuthService,
    private readonly _modal: UiModalService,
  ) {
    this.updateClient();
    IsaLogProvider.InfoService = this.infoService;
  }

  ngOnInit() {
    this.setTitle();
    this.logVersion();
    asapScheduler.schedule(() => this.determinePlatform(), 250);
    this._appService.getSection$().subscribe(this.sectionChangeHandler.bind(this));

    this.setupSilentRefresh();
  }

  // Setup interval for silent refresh
  setupSilentRefresh() {
    const silentRefreshInterval = this._config.get('silentRefresh.interval');
    if (silentRefreshInterval > 0) {
      interval(silentRefreshInterval).subscribe(() => {
        if (this._authService.isAuthenticated()) {
          this._authService.refresh();
        }
      });
    }
  }

  setTitle() {
    this._title.setTitle(this._config.get('title'));
  }

  logVersion() {
    console.log(
      `%c${this._config.get('title')}\r\nVersion: ${packageInfo.version}`,
      'font-weight: bold; font-size: 20px;',
    );
  }

  determinePlatform() {
    if (this._environment.isNative()) {
      this._renderer.addClass(this._document.body, 'tablet-native');
    } else if (this._environment.isTablet()) {
      this._renderer.addClass(this._document.body, 'tablet-browser');
    }
    if (this._environment.isTablet()) {
      this._renderer.addClass(this._document.body, 'tablet');
    }
    if (this._environment.isDesktop()) {
      this._renderer.addClass(this._document.body, 'desktop');
    }
  }

  sectionChangeHandler(section: string) {
    if (section === 'customer') {
      this._renderer.removeClass(this._document.body, 'branch');
      this._renderer.addClass(this._document.body, 'customer');
    } else if (section === 'branch') {
      this._renderer.removeClass(this._document.body, 'customer');
      this._renderer.addClass(this._document.body, 'branch');
    }
  }

  updateClient() {
    if (!this._swUpdate.isEnabled) {
      return;
    }

    this.initialCheckForUpdate();
    this.checkForUpdate();
  }

  checkForUpdate() {
    interval(this._checkForUpdates).subscribe(() => {
      this._swUpdate.checkForUpdate().then((value) => {
        console.log('check for update', value);
        if (value) {
          this._notifications.updateNotification();
        }
      });
    });
  }

  initialCheckForUpdate() {
    this._swUpdate.checkForUpdate().then((value) => {
      console.log('initial check for update', value);
      if (value) {
        location.reload();
      }
    });
  }

  @HostListener('window:visibilitychange', ['$event'])
  onVisibilityChange(event: Event) {
    // refresh token when app is in background
    if (this._document.hidden && this._authService.isAuthenticated()) {
      this._authService.refresh();
    } else if (!this._authService.isAuthenticated()) {
      const strategy = this.injector.get(LoginStrategy);

      return strategy.login('Sie sind nicht mehr angemeldet');
    }
  }
}
