import { signal, computed } from '@angular/core';
import { QrLoginAdapter, QrLoginStatus } from './qr-login.model';

const POLL_INTERVAL_MS = 5000;
const MAX_POLLS = 100;

/**
 * Shared QR-login state machine: session creation, polling, expiry, and the
 * "returned from the messenger app" recovery flow (visibilitychange/focus/pageshow).
 * Extracted from the original TelegramLoginComponent so admin login (and any
 * future QR login surface) can reuse it instead of duplicating timers/listeners.
 * Not a DI singleton — instantiate one per component instance.
 */
export class QrLoginEngine<TSession> {
  readonly loginUrl = signal('');
  readonly webSessionID = signal('');
  readonly qrStatus = signal<QrLoginStatus>('loading');
  readonly encodedQrUrl = computed(() => encodeURIComponent(this.loginUrl()));
  readonly awaitingAppReturn = signal(false);

  private pollTimer?: ReturnType<typeof setInterval>;
  private active = false;

  private readonly handleVisibilityChange = () => {
    if (typeof document !== 'undefined' && document.visibilityState === 'visible') {
      this.checkAfterReturn();
    }
  };
  private readonly handleWindowFocus = () => this.checkAfterReturn();
  private readonly handlePageShow = () => this.checkAfterReturn();

  constructor(private readonly adapter: QrLoginAdapter<TSession>) {
    if (typeof window !== 'undefined') {
      document.addEventListener('visibilitychange', this.handleVisibilityChange);
      window.addEventListener('focus', this.handleWindowFocus);
      window.addEventListener('pageshow', this.handlePageShow);
    }
  }

  /** Call from an effect() watching the dialog-visibility signal. */
  setActive(active: boolean): void {
    this.active = active;
    if (active) {
      this.init();
    } else {
      this.awaitingAppReturn.set(false);
      this.stopPolling();
    }
  }

  refresh(): void {
    this.awaitingAppReturn.set(false);
    this.stopPolling();
    this.init();
  }

  openAppLogin(): void {
    const webSessionID = this.webSessionID();
    if (!webSessionID || typeof window === 'undefined') return;

    if (!this.pollTimer) {
      this.startPolling(webSessionID);
    }

    this.awaitingAppReturn.set(true);
    window.location.href = this.adapter.getAppLoginUrl(webSessionID);
  }

  destroy(): void {
    this.awaitingAppReturn.set(false);
    this.stopPolling();

    if (typeof window !== 'undefined') {
      document.removeEventListener('visibilitychange', this.handleVisibilityChange);
      window.removeEventListener('focus', this.handleWindowFocus);
      window.removeEventListener('pageshow', this.handlePageShow);
    }
  }

  private init(): void {
    this.awaitingAppReturn.set(false);
    this.qrStatus.set('loading');
    this.loginUrl.set('');
    this.webSessionID.set('');

    this.adapter.createSession().subscribe({
      next: res => {
        this.loginUrl.set(res.url);
        this.webSessionID.set(res.webSessionID);
        this.qrStatus.set('ready');
        this.startPolling(res.webSessionID);
      },
      error: () => this.qrStatus.set('error'),
    });
  }

  private startPolling(webSessionID: string): void {
    this.stopPolling();
    if (!webSessionID) return;

    let checks = 0;
    this.pollTimer = setInterval(() => {
      checks++;
      if (checks > MAX_POLLS) {
        this.stopPolling();
        this.qrStatus.set('expired');
        return;
      }

      this.adapter.checkSessionOnce(webSessionID).subscribe({
        next: session => {
          if (this.adapter.isSessionActive(session)) {
            this.awaitingAppReturn.set(false);
            this.stopPolling();
            this.adapter.onLoginComplete();
          }
        },
        error: () => {
          // network error - keep polling
        },
      });
    }, POLL_INTERVAL_MS);
  }

  private stopPolling(): void {
    if (this.pollTimer) {
      clearInterval(this.pollTimer);
      this.pollTimer = undefined;
    }
  }

  private checkAfterReturn(): void {
    if (!this.active || !this.awaitingAppReturn()) {
      return;
    }

    const webSessionID = this.webSessionID();
    if (!webSessionID) {
      this.awaitingAppReturn.set(false);
      return;
    }

    if (!this.pollTimer) {
      this.startPolling(webSessionID);
    }

    this.adapter.checkSessionOnce(webSessionID).subscribe(session => {
      if (this.adapter.isSessionActive(session)) {
        this.awaitingAppReturn.set(false);
        this.stopPolling();
        this.adapter.onLoginComplete();
      }
    });
  }
}
