import { Injectable, signal, effect, inject, computed } from '@angular/core';
import { CantiService } from './canti.service';
import { SettingsService } from './settings.service';
import { MediaSessionService } from './media-session.service';
import { MyCantiService } from './my-canti.service';
import { ConnectivityService } from './connectivity.service';
import { ComunitaService } from './comunita.service';

@Injectable({
  providedIn: 'root'
})
export class YoutubePlayerService {
  private cantiService = inject(CantiService);
  private settingsService = inject(SettingsService);
  private mediaSessionService = inject(MediaSessionService);
  private myCantiService = inject(MyCantiService);
  private connectivityService = inject(ConnectivityService);
  private comunitaService = inject(ComunitaService);

  public isPlayerSupported = computed<boolean>(() => {
    // Check if offline
    if (!this.connectivityService.isOnline()) {
      return false;
    }
    return true;
  });

  public currentCantoId = signal<string | null>(null);
  public isPlaying = signal<boolean>(false);
  public videoProgress = signal<number>(0);
  public videoDuration = signal<number>(0);
  public isPlayerReady = signal<boolean>(false);

  private player: any = null;
  private progressInterval: any = null;
  private onEndedCallback: (() => void) | null = null;
  private onErrorCallback: (() => void) | null = null;
  private silentAudio: HTMLAudioElement | null = null;
  private lastNextCallback: (() => void) | null = null;
  private lastPrevCallback: (() => void) | null = null;

  constructor() {
    this.loadYoutubeAPI();
    this.setupMediaSession();
    this.initSilentAudio();
    this.setupBackgroundPersistence();

    // Auto-stop player when not supported (e.g. going offline)
    effect(() => {
      const supported = this.isPlayerSupported();
      if (!supported && this.currentCantoId()) {
        this.stop();
      }
    });
  }

  private initSilentAudio() {
    // 1-second silent MP3 base64
    const silentSrc = 'data:audio/mpeg;base64,SUQzBAAAAAABAFRYWFhYAAAADAAAY29udGVudAB0eXBlAGF1ZGlvL21wZWdB///+8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
    this.silentAudio = new Audio(silentSrc);
    this.silentAudio.loop = true;
  }

  private setupBackgroundPersistence() {
    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'visible' && this.isPlaying() && this.player) {
        // Ensure player is actually playing when returning to the app
        try {
          if (this.player.getPlayerState() !== (window as any).YT.PlayerState.PLAYING) {
            this.player.playVideo();
          }
        } catch (e) {}
      }
    });
  }

  public setMediaSessionCallbacks(next?: () => void, prev?: () => void) {
    if (next) this.lastNextCallback = next;
    if (prev) this.lastPrevCallback = prev;
    
    this.mediaSessionService.initActionHandlers({
      play: () => this.resume(),
      pause: () => this.pause(),
      seekto: (time) => this.seekTo(time),
      next: this.lastNextCallback || undefined,
      prev: this.lastPrevCallback || undefined
    });
  }

  private setupMediaSession() {
    this.setMediaSessionCallbacks();
  }

  private loadYoutubeAPI() {
    if ((window as any).YT) return;
    const tag = document.createElement('script');
    tag.src = "https://www.youtube.com/iframe_api";
    const firstScriptTag = document.getElementsByTagName('script')[0];
    firstScriptTag.parentNode?.insertBefore(tag, firstScriptTag);

    (window as any).onYouTubeIframeAPIReady = () => {
      this.isPlayerReady.set(true);
    };
  }

  public initPlayer(cantoId: string, startTime: number = 0, onEnded?: () => void, onError?: () => void) {
    if (this.currentCantoId() === cantoId && this.player) {
      this.onEndedCallback = onEnded || null;
      this.onErrorCallback = onError || null;
      
      const currentTime = this.player.getCurrentTime();
      // Only seek if the difference is significant (more than 2 seconds)
      if (startTime > 0 && Math.abs(currentTime - startTime) > 2) {
        this.player.seekTo(startTime, true);
      }
      this.resume();
      return;
    }

    this.onEndedCallback = onEnded || null;
    this.onErrorCallback = onError || null;
    
    let canto = this.cantiService.getCantoById(cantoId);
    if (!canto) {
      canto = this.myCantiService.myCanti().find(c => c.id === cantoId);
    }
    if (!canto) {
      canto = this.comunitaService.comunitaCantiPersonali().find(c => c.id === cantoId);
    }
    if (!canto) return;

    const videoId = this.cantiService.getYoutubeId(canto.link_youtube);
    if (!videoId) {
      if (onError) onError();
      return;
    }

    if (!(window as any).YT || !(window as any).YT.Player) {
      setTimeout(() => this.initPlayer(cantoId, startTime, onEnded, onError), 200);
      return;
    }

    // Reuse existing player if possible
    if (this.player && this.player.loadVideoById) {
      this.currentCantoId.set(cantoId);
      this.mediaSessionService.updateMetadata(cantoId);
      this.player.loadVideoById({
        videoId: videoId,
        startSeconds: startTime
      });
      if (this.silentAudio) this.silentAudio.play().catch(() => {});
      return;
    }

    this.destroyPlayer();
    this.currentCantoId.set(cantoId);
    this.mediaSessionService.updateMetadata(cantoId);

    this.player = new (window as any).YT.Player('global-yt-player-container', {
      height: '1',
      width: '1',
      videoId: videoId,
      playerVars: {
        autoplay: 1,
        playsinline: 1,
        mute: 0,
        modestbranding: 1,
        rel: 0,
        controls: 0,
        disablekb: 1,
        start: startTime
      },
      events: {
        onReady: (event: any) => {
          event.target.unMute();
          event.target.setVolume(100);
          this.videoDuration.set(event.target.getDuration());
          this.startPolling();
          if (startTime > 0) {
            event.target.seekTo(startTime, true);
          }
          event.target.playVideo();
          this.isPlaying.set(true);
          if (this.silentAudio) this.silentAudio.play().catch(() => {});
        },
        onStateChange: (event: any) => {
          const state = event.data;
          if (state === (window as any).YT.PlayerState.PLAYING) {
            this.isPlaying.set(true);
            this.videoDuration.set(this.player.getDuration());
            this.mediaSessionService.setPlaybackState('playing');
            // Re-apply handlers to prevent YT from overriding them
            this.setMediaSessionCallbacks(); 
          } else if (state === (window as any).YT.PlayerState.PAUSED) {
            this.isPlaying.set(false);
            this.mediaSessionService.setPlaybackState('paused');
            // Re-apply handlers even when paused
            this.setMediaSessionCallbacks();
          } else if (state === (window as any).YT.PlayerState.ENDED) {
            this.isPlaying.set(false);
            this.mediaSessionService.setPlaybackState('none');
            if (this.onEndedCallback) this.onEndedCallback();
          }
        },
        onError: (event: any) => {
          console.error('Global YT Player Error:', event.data);
          if (this.onErrorCallback) this.onErrorCallback();
        }
      }
    });
  }

  public pause() {
    if (this.player) {
      this.player.pauseVideo();
      this.isPlaying.set(false);
      if (this.silentAudio) this.silentAudio.pause();
    }
  }

  public resume() {
    if (this.player) {
      this.player.playVideo();
      this.isPlaying.set(true);
      if (this.silentAudio) this.silentAudio.play().catch(() => {});
    }
  }

  public togglePlayPause() {
    if (this.isPlaying()) {
      this.pause();
    } else {
      this.resume();
    }
  }

  public seekTo(seconds: number) {
    if (this.player) {
      this.player.seekTo(seconds, true);
    }
  }

  public stop() {
    this.destroyPlayer();
    this.currentCantoId.set(null);
    this.isPlaying.set(false);
  }

  private startPolling() {
    if (this.progressInterval) clearInterval(this.progressInterval);
    this.progressInterval = setInterval(() => {
      if (this.player && this.player.getCurrentTime) {
        this.videoProgress.set(this.player.getCurrentTime());
      }
    }, 500);
  }

  private destroyPlayer() {
    if (this.progressInterval) {
      clearInterval(this.progressInterval);
      this.progressInterval = null;
    }
    if (this.player) {
      try {
        this.player.destroy();
      } catch (e) {}
      this.player = null;
    }
  }
}
