import videojs from "video.js";
import shaka from "shaka-player";
import { setupShakaDRM } from "./shaka-drm-config";
import setupQualityTracks from "./setup-quality-tracks";
import setupTextTracks from "./setup-text-tracks";
import setupAudioTracks from "./setup-audio-tracks";

const Html5 = videojs.getTech("Html5");

class Shaka extends Html5 {
  constructor(options, ready) {
    super(options, ready);

    this.vjsPlayer = videojs(options.playerId);
    this.shaka_ = null;

    this.player_.ready(() => {
      this.player_.addClass("vjs-shaka");
    });
  }

  static isSupported() {
    return !!window.MediaSource && shaka.Player.isBrowserSupported();
  }

  static canPlaySource(sourceObj, type) {
    const dashTypeRE = /^(application\/dash\+xml|application\/x-mpegURL)/i;

    if (dashTypeRE.test(sourceObj.type)) {
      return "probably";
    }

    return "";
  }

  createEl() {
    this.el_ = Html5.prototype.createEl.apply(this, arguments);

    // Install built-in polyfills to patch browser incompatibilities.
    shaka.polyfill.installAll();

    // Set debug log level
    if (shaka.log) {
      if (this.options_.debug) {
        shaka.log.setLevel(shaka.log.Level.DEBUG);
      } else {
        shaka.log.setLevel(shaka.log.Level.ERROR);
      }
    }

    this.el_.tech = this;

    return this.el_;
  }

  initializeShaka() {
    if (!this.shaka_ && this.el_) {
      console.log("Initializing Shaka Player...");
      this.shaka_ = new shaka.Player(this.el_);
      // this.shaka_.configure({
      //   streaming: {
      //     useNativeHlsForFairPlay: false,
      //     preferNativeHls: false,
      //   },
      // });
      console.log("Shaka Player initialized");
    } else if (!this.el_) {
      console.log("Element not created, cannot initialize Shaka Player");
    }
  }

  async setSrc(src) {
    const me = this;

    // Ensure element and Shaka Player are initialized
    if (!this.el_) {
      console.log("Element has not been created, waiting...");
      // Add retry up to 3 times when waiting for this.el_
      if (typeof this._elRetryCount === "undefined") {
        this._elRetryCount = 0;
      }
      this._elRetryCount++;
      if (this._elRetryCount > 3) {
        console.error(
          "Cannot create element for Shaka Player after 3 retries."
        );
        return;
      }
      setTimeout(() => {
        me.setSrc(src);
      }, 100);
      return;
    }

    if (!this.shaka_) {
      console.log("Shaka Player has not been initialized, initializing...");
      this.initializeShaka();
    }

    if (!this.shaka_) {
      console.log("Cannot initialize Shaka Player");
      return;
    }

    const shakaOptions = this.options_.configuration || {};

    if (!shakaOptions.abr) {
      shakaOptions.abr = {
        enabled: true,
      };
    }

    if (this.options_.drmConfig) {
      await setupShakaDRM(this.shaka_, this.options_.drmConfig);
    }

    this.shaka_.addEventListener("buffering", function (event) {
      if (event.buffering) {
        me.vjsPlayer.trigger("waiting");
      } else {
        me.vjsPlayer.trigger("playing");
      }
    });

    this.shaka_.addEventListener("error", function (event) {
      me.retriggerError(event.detail);
    });

    this.shaka_
      .load(src)
      .then(function () {
        me.initShakaMenus();
      })
      .catch(me.retriggerError.bind(this));
  }

  dispose() {
    if (this.shaka_) {
      this.shaka_.unload();
      this.shaka_.destroy();
    }
    super.dispose();
  }

  initShakaMenus() {
    // Setup quality tracks, text tracks, audio tracks
    console.log('Setting up Shaka menus...');
    
    try {
      // Setup quality tracks (renditions)
      setupQualityTracks(this, this.shaka_);
      console.log('Quality tracks setup completed');
      
      // Setup text tracks (subtitles)
      setupTextTracks(this, this.shaka_);
      console.log('Text tracks setup completed');
      
      // Setup audio tracks
      setupAudioTracks(this, this.shaka_);
      console.log('Audio tracks setup completed');
    } catch (error) {
      console.error('Error setting up Shaka:', error);
    }
  }

  retriggerError(event) {
    let code;

    // map the shaka player error to the appropriate video.js error
    if (
      event.message &&
      (event.message.indexOf("UNSUPPORTED") > -1 ||
        event.message.indexOf("NOT_SUPPORTED") > -1)
    ) {
      code = 4;
    } else {
      switch (event.category) {
        case 1:
          code = 2;
          break;
        case 2:
        case 3:
        case 4:
          code = 3;
          break;
        case 5:
          code = 1;
          break;
        case 6:
          code = 5;
          break;
        case 7:
        case 8:
        case 9:
          code = 0;
          break;
      }
    }

    this.vjsPlayer.error({
      code,
      message: `${event.code} - ${event.message}`,
    });

    // only reset the shaka player in 10ms async, so that the rest of the
    // calling function finishes
    setTimeout(() => {
      this.dispose();
    }, 10);
  }

  getShaka_() {
    return this.shaka_;
  }
}

export default Shaka;
