import videojs from "video.js";
import "video.js/dist/video-js.css";
import { setupDRM } from "./drm-config";
import CustomControlBar from "./components/CustomControlBar";
import Shaka from "./shaka/shaka.js";
import "./styles/styles.css";

// Define default values for the plugin's `state` object here.
Shaka.defaultState = {};

// Register tech with Video.js
videojs.registerTech("shaka", Shaka);

class VideoJSDRMPlayer {
  constructor(options = {}) {
    // Validate required parameters
    if (!options.videoId) {
      throw new Error("videoId parameter is required");
    }

    if (!options.source) {
      throw new Error("source parameter is required");
    }

    this.options = {
      // Default options
      width: 100,
      isDRM: false,
      useShakaTech: false,
      // Merge with user options
      ...options,
    };

    this.videoId = options.videoId;
    this.source = options.source;
    this.isDRM = options.isDRM ?? false;
    this.player = null;

    this.init();
  }

  async init() {
    // Create video element
    this.createVideoElement();

    // Initialize Video.js player
    this.initializePlayer();
  }

  createVideoElement() {
    const videoElement = document.getElementById(this.videoId);
    if (!videoElement) {
      throw new Error(`Video element with id "${this.videoId}" not found`);
    }

    // Check if drmConfig is required
    if (
      this.options.isDRM &&
      (!this.options.drmConfig || !Object.keys(this.options.drmConfig).length)
    ) {
      throw new Error("drmConfig parameter is required if isDRM is true");
    }

    this.dispose();

    // Configure the existing video element
    videoElement.className = "video-js vjs-default-skin";
    videoElement.playsinline = true;
    videoElement["webkit-playsinline"] = true;

    this.videoElement = videoElement;
  }

  initializePlayer() {
    const playerOptions = {
      ...this.getVideoJSOptions(),
      controls: false,
      techOrder: this.options.useShakaTech ? ["shaka", "html5"] : ["html5"],
    };

    this.player = videojs(this.videoElement, playerOptions);

    if (!this.player) {
      throw new Error("Failed to initialize Video.js player");
    }

    if (this.options.fluid) {
      this.videoElement.classList.add("vjs-fluid");
      this.player.fluid(true);
    }

    window.addEventListener("beforeunload", function () {
      this.dispose();
    });

    // Add error handling
    this.player.on("error", (error) => {
      console.error("Video.js Player Error:", error);
      this.emit("error", error);
    });

    // Add ready event
    this.player.ready(() => {
      console.log("Video.js Player is ready");

      // Setup DRM if needed
      if (!this.options.useShakaTech && this.isDRM) {
        this.setupDRMSupport();
      } else {
        this.loadSource();
      }

      this.emit("ready");

      const customControlBar = new CustomControlBar(this.player, {});
      this.player.el().appendChild(customControlBar.el());

      // Detect audio-only after metadata is available
      this.player.on("loadedmetadata", () => {
        // Wait for 500ms to ensure metadata is loaded (for Safari)
        setTimeout(() => {
          this.applyAudioOnlyModeIfNeeded();
        }, 500);
      });

      // Also re-check on source changes
      // this.player.on("loadstart", () => {
      //   // remove previous state until metadata loads
      //   this.updateAudioOnlyClass(false);
      // });
    });
  }

  getVideoJSOptions() {
    const videojsOptions = { ...this.options };

    // Remove our custom options
    delete videojsOptions.videoId;
    delete videojsOptions.source;
    delete videojsOptions.isDRM;
    if (this.options.useShakaTech && this.options.isDRM) {
      videojsOptions.shaka = {
        drmConfig: this.options.drmConfig,
      };
    } else {
      delete videojsOptions.drmConfig;
    }
    delete videojsOptions.controls;

    return videojsOptions;
  }

  setupDRMSupport() {
    setupDRM(
      this.player,
      {
        url: this.source,
        type: this.detectSourceType(this.source),
      },
      this.options.drmConfig
    );
  }

  loadSource() {
    const sourceConfig = {
      src: this.source,
      type: this.detectSourceType(this.source),
    };

    this.player.src(sourceConfig);
  }

  detectSourceType(source) {
    const extension = source.split(".").pop().toLowerCase();
    const typeMap = {
      mp4: "video/mp4",
      webm: "video/webm",
      ogv: "video/ogg",
      // Audio types
      mp3: "audio/mpeg",
      m4a: "audio/mp4",
      aac: "audio/aac",
      wav: "audio/wav",
      oga: "audio/ogg",
      ogg: "audio/ogg",
      // Encrypted Media Extensions
      m3u8: "application/x-mpegURL",
      mpd: "application/dash+xml",
    };

    return typeMap[extension] || "video/mp4";
  }

  isAudioMime(type) {
    return typeof type === "string" && type.startsWith("audio/");
  }

  applyAudioOnlyModeIfNeeded() {
    try {
      const currentSrc = this.player?.currentSource?.() || {};
      const srcType = currentSrc.type || this.detectSourceType(this.source);

      let isAudioOnly = this.isAudioMime(srcType);

      // Check intrinsic video dimensions from tech
      if (!isAudioOnly && typeof this.player?.videoWidth === "function") {
        const vw = this.player.videoWidth();
        const vh = this.player.videoHeight();
        if ((vw === 0 && vh === 0) || Number.isNaN(vw) || Number.isNaN(vh)) {
          isAudioOnly = true;
        }
      }

      this.updateAudioOnlyClass(!!isAudioOnly);
    } catch (e) {
      this.updateAudioOnlyClass(false);
    }
  }

  updateAudioOnlyClass(isAudioOnly) {
    if (!this.player || !this.player.el()) return;
    const root = this.player.el();
    if (isAudioOnly) {
      root.classList.add("audio-only");
    } else {
      root.classList.remove("audio-only");
    }
  }

  // Custom event system
  emit(eventName, data = null) {
    const event = new CustomEvent(
      `${this.videoId}-videojs-drm-player:${eventName}`,
      {
        detail: data,
      }
    );
    document.dispatchEvent(event);
  }

  on(eventName, callback) {
    document.addEventListener(
      `${this.videoId}-videojs-drm-player:${eventName}`,
      callback
    );
  }

  // Public API methods
  play() {
    if (this.player) {
      return this.player.play();
    }
  }

  pause() {
    if (this.player) {
      this.player.pause();
    }
  }

  stop() {
    if (this.player) {
      this.player.pause();
      this.player.currentTime(0);
    }
  }

  rewind(seconds = 10) {
    if (this.player) {
      const currentTime = this.player.currentTime();
      this.player.currentTime(Math.max(0, currentTime - seconds));
    }
  }

  forward(seconds = 10) {
    if (this.player) {
      const currentTime = this.player.currentTime();
      const duration = this.player.duration();
      this.player.currentTime(Math.min(duration, currentTime + seconds));
    }
  }

  setVolume(volume) {
    if (this.player && volume >= 0 && volume <= 1) {
      this.player.volume(volume);
    }
  }

  getVolume() {
    return this.player ? this.player.volume() : 0;
  }

  mute() {
    if (this.player) {
      this.player.muted(true);
    }
  }

  unmute() {
    if (this.player) {
      this.player.muted(false);
    }
  }

  toggleMute() {
    if (this.player) {
      this.player.muted(!this.player.muted());
    }
  }

  getCurrentTime() {
    return this.player ? this.player.currentTime() : 0;
  }

  getDuration() {
    return this.player ? this.player.duration() : 0;
  }

  seek(time) {
    if (this.player && time >= 0) {
      this.player.currentTime(time);
    }
  }

  setSize(width, height) {
    if (this.player) {
      this.player.dimensions(width, height);
      this.options.width = width;
      this.options.height = height;
    }
  }

  // Cleanup method
  dispose() {
    if (this.player && !this.player.isDisposed()) {
      this.player.dispose();
      this.player = null;
    }

    // Don't remove the video element since it's provided by the user
    // Just reset the reference
    this.videoElement = null;
  }
}

// Export for different module systems
export default VideoJSDRMPlayer;

// Also make it available globally if not using modules
if (typeof window !== "undefined") {
  window.VideoJSDRMPlayer = VideoJSDRMPlayer;
}
