import { Injectable, OnDestroy, signal } from '@angular/core';

export interface CheckoutTiming {
  expires_at: string | null;
  expires_in_seconds: number | null;
  server_time: string;
}

@Injectable({
  providedIn: 'root',
})
export class CheckoutCountdownService implements OnDestroy {
  private readonly remainingSecondsState = signal<number | null>(null);
  private deadlineMs: number | null = null;
  private intervalId: ReturnType<typeof setInterval> | null = null;

  readonly remainingSeconds = this.remainingSecondsState.asReadonly();

  synchronize(timing: Partial<CheckoutTiming>): void {
    const remainingSeconds = this.resolveRemainingSeconds(timing);

    if (remainingSeconds === undefined) {
      return;
    }

    if (remainingSeconds === null) {
      this.clear();
      return;
    }

    this.stopInterval();
    this.deadlineMs = Date.now() + remainingSeconds * 1_000;
    this.updateRemainingSeconds();

    if (remainingSeconds > 0) {
      this.intervalId = setInterval(() => this.updateRemainingSeconds(), 1_000);
    }
  }

  clear(): void {
    this.stopInterval();
    this.deadlineMs = null;
    this.remainingSecondsState.set(null);
  }

  ngOnDestroy(): void {
    this.clear();
  }

  private resolveRemainingSeconds(timing: Partial<CheckoutTiming>): number | null | undefined {
    if (timing.expires_at === null && timing.expires_in_seconds === null) {
      return null;
    }

    const expiresAt =
      typeof timing.expires_at === 'string' ? Date.parse(timing.expires_at) : Number.NaN;
    const serverTime =
      typeof timing.server_time === 'string' ? Date.parse(timing.server_time) : Number.NaN;

    if (Number.isFinite(expiresAt) && Number.isFinite(serverTime)) {
      return Math.max(0, Math.ceil((expiresAt - serverTime) / 1_000));
    }

    if (
      typeof timing.expires_in_seconds === 'number' &&
      Number.isFinite(timing.expires_in_seconds)
    ) {
      return Math.max(0, Math.ceil(timing.expires_in_seconds));
    }

    if (Number.isFinite(expiresAt)) {
      return Math.max(0, Math.ceil((expiresAt - Date.now()) / 1_000));
    }

    return undefined;
  }

  private updateRemainingSeconds(): void {
    if (this.deadlineMs === null) {
      return;
    }

    const remainingSeconds = Math.max(0, Math.ceil((this.deadlineMs - Date.now()) / 1_000));
    this.remainingSecondsState.set(remainingSeconds);

    if (remainingSeconds === 0) {
      this.stopInterval();
    }
  }

  private stopInterval(): void {
    if (this.intervalId !== null) {
      clearInterval(this.intervalId);
      this.intervalId = null;
    }
  }
}
