import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BehaviorSubject, lastValueFrom, Observable } from 'rxjs';
import { environment } from '../environments/environment';

@Injectable({
  providedIn: 'root',
})
export class MovieService {
  private movieCache: { [key: number]: { [resolution: string]: boolean } } = {};

  constructor(private http: HttpClient) {}

  getAllMovies(): Promise<any> {
    const url = environment.baseUrl + '/content/';
    const headers = this.getAuthHeaders();
    return lastValueFrom(this.http.get(url, { headers }));
  }

  getMovieFiles(videoUrl: number): Promise<any> {
    const url = environment.baseUrl + `${videoUrl}`;
    const headers = this.getAuthHeaders();
    return lastValueFrom(this.http.get(url, { headers }));
  }

  uploadMovie(formData: FormData) {
    const url = environment.baseUrl + '/content/upload/';
    const headers = this.getAuthHeaders();
    return lastValueFrom(this.http.post(url, formData, { headers }));
  }

  private getAuthHeaders(): HttpHeaders {
    let authToken = localStorage.getItem('authToken');
    if (!authToken) {
      authToken = sessionStorage.getItem('authToken');
    }
    return new HttpHeaders({
      Authorization: `Token ${authToken}`,
    });
  }

  /**
   * Checks if a movie is uploaded in multiple resolutions.
   *
   * @param {number} videoID - The ID of the movie to check.
   * @returns {Observable<{ [resolution: string]: boolean }>} Observable emitting an object with the availability of each resolution.
   */
  isMovieResolutionUploaded(
    videoID: number
  ): Observable<{ [resolution: string]: boolean }> {
    if (this.movieCache.hasOwnProperty(videoID)) {
      const cachedResolutions = this.movieCache[videoID];

      const missingResolutions = Object.keys(cachedResolutions).filter(
        (res) => !cachedResolutions[res]
      );

      if (missingResolutions.length === 0) {
        return new BehaviorSubject(cachedResolutions).asObservable();
      } else {
        return this.fetchAndCacheResolutions(videoID);
      }
    } else {
      return this.fetchAndCacheResolutions(videoID);
    }
  }

  /**
   * Fetches the availability of multiple resolutions for a specific movie.
   *
   * @param {number} videoID - The ID of the movie to fetch resolutions for.
   * @returns {Observable<{ [resolution: string]: boolean }>} Observable emitting an object with the availability of each resolution.
   */
  private fetchAndCacheResolutions(
    videoID: number
  ): Observable<{ [resolution: string]: boolean }> {
    const url = `${environment.baseUrl}/content/movie/${videoID}/`;
    const headers = this.getAuthHeaders();

    return new Observable<{ [resolution: string]: boolean }>((observer) => {
      this.http.get(url, { headers }).subscribe(
        (response: any) => {
          const resolutions = {
            '360': response['360'] || false,
            '720': response['720'] || false,
            '1080': response['1080'] || false,
          };
          this.movieCache[videoID] = resolutions;
          observer.next(resolutions);
          observer.complete();
        },
        (error) => {
          observer.next(
            this.movieCache[videoID] || {
              '360': false,
              '720': false,
              '1080': false,
            }
          );
          observer.complete();
        }
      );
    });
  }
}
