import { Injectable } from '@angular/core';
import { environment } from '../../environments/environment';
import * as jose from 'jose';
import { BehaviorSubject, Observable, timer, Subscription } from 'rxjs';
import { map, takeWhile, finalize } from 'rxjs/operators';
import { Router } from '@angular/router';
import { ToastrService } from 'ngx-toastr';

@Injectable({
  providedIn: 'root'
})
export class JwtService {
  private secret = new TextEncoder().encode(environment.jwt_secret);
  private countdownSub = new BehaviorSubject<string | null>(null);
  public countdown$: Observable<string | null> = this.countdownSub.asObservable();
  private timerSubscription: Subscription | null = null;

  constructor(
    private router: Router,
    private toastr: ToastrService
  ) {
    this.startTokenCountdown();
  }

  async decodeToken(token: string): Promise<any> {
    try {
      const { payload } = await jose.jwtVerify(token, this.secret);
      return payload;
    } catch (error) {
      // console.error('Invalid token:', error);
      return null;
    }
  }

  private startTokenCountdown(): void {
    if (this.timerSubscription) {
      this.timerSubscription.unsubscribe();
    }

    const token = localStorage.getItem('access_token');
    if (!token) {
      this.countdownSub.next(null);
      return;
    }

    this.decodeToken(token).then(payload => {
      if (payload && payload.exp) {
        const expirationTime = payload.exp * 1000;
        this.timerSubscription = timer(0, 1000).pipe(
          map(() => {
            const now = new Date().getTime();
            const distance = expirationTime - now;

            if (distance < 0) {
              this.logout();
              return 'Expired';
            }

            const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
            const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
            const seconds = Math.floor((distance % (1000 * 60)) / 1000);

            return `${this.pad(hours)}:${this.pad(minutes)}:${this.pad(seconds)}`;
          }),
          takeWhile(val => val !== 'Expired', true),
          finalize(() => {
            if (this.countdownSub.value !== 'Expired') {
                this.logout();
            }
            this.countdownSub.next('Expired');
          })
        ).subscribe(val => this.countdownSub.next(val));
      } else {
        this.countdownSub.next(null);
      }
    });
  }

  private pad(num: number): string {
    return num < 10 ? '0' + num : num.toString();
  }

  public logout(): void {
    localStorage.removeItem('access_token');
    this.countdownSub.next(null);
    if (this.timerSubscription) {
      this.timerSubscription.unsubscribe();
    }
    // this.toastr.info('Your session has expired. Please log in again.', 'Session Expired');
    this.router.navigate(['/login']); // Assuming '/login' is your login route
  }

  public restartCountdown(): void {
    this.startTokenCountdown();
  }
}
