import videojs from "video.js";
import "./ProgressBar.css";

const Component = videojs.getComponent("Component");

class ProgressBar extends Component {
  constructor(player, options) {
    super(player, options);

    this.isDragging = false;
    this.isTouchDragging = false;
    this.tooltipTimeout = null;
  }

  createEl() {
    const el = super.createEl("div", {
      className: "custom-progress-container",
    });

    // Create progress bar HTML structure
    el.innerHTML = `
        <div class="custom-progress-loaded"></div>
        <div class="custom-progress-played"></div>
        <div class="custom-progress-handle"></div>
        <div class="custom-progress-tooltip">00:00</div>
    `;

    return el;
  }

  ready() {
    super.ready();
    this.setupProgressBar();
  }

  setupProgressBar() {
    const loadedBar = this.el().querySelector(".custom-progress-loaded");
    const playedBar = this.el().querySelector(".custom-progress-played");
    const handle = this.el().querySelector(".custom-progress-handle");
    const tooltip = this.el().querySelector(".custom-progress-tooltip");

    // Update progress display
    const updateProgress = () => {
      const currentTime = this.player().currentTime() || 0;
      const duration = this.player().duration() || 0;
      const buffered = this.player().buffered();

      if (duration > 0) {
        const playedPercent = (currentTime / duration) * 100;
        playedBar.style.width = `${playedPercent}%`;
        handle.style.left = `${playedPercent}%`;

        // Update loaded progress
        if (buffered.length > 0) {
          const loadedPercent =
            (buffered.end(buffered.length - 1) / duration) * 100;
          loadedBar.style.width = `${loadedPercent}%`;
        }
      }
    };

    // Handle click/tap to seek
    const seekToPosition = (e) => {
      const rect = this.el().getBoundingClientRect();
      const clientX =
        e.clientX || (e.touches && e.touches[0] ? e.touches[0].clientX : 0);
      const percent = Math.max(
        0,
        Math.min(1, (clientX - rect.left) / rect.width)
      );
      const duration = this.player().duration();
      const seekTime = percent * duration;

      if (duration && !isNaN(duration)) {
        this.player().currentTime(seekTime);
      }
    };

    // Helper function to format time
    const formatTime = (seconds) => {
      if (isNaN(seconds) || seconds < 0) {
        seconds = 0;
      }
      const date = new Date(null);
      date.setSeconds(seconds);
      const result = date.toISOString().substr(11, 8);
      return result.startsWith("00:") ? result.substr(3) : result;
    };

    // Update tooltip based on mouse/touch position
    const updateTooltipPosition = (e) => {
      const rect = this.el().getBoundingClientRect();
      const clientX =
        e.clientX || (e.touches && e.touches[0] ? e.touches[0].clientX : 0);
      const percent = Math.max(
        0,
        Math.min(1, (clientX - rect.left) / rect.width)
      );
      const duration = this.player().duration();

      if (duration && !isNaN(duration)) {
        const seekTime = percent * duration;
        tooltip.textContent = formatTime(seekTime);

        // Position tooltip at mouse/touch position
        const leftPercent = percent * 100;
        tooltip.style.left =
          leftPercent < 1
            ? "3px"
            : leftPercent > 99
            ? "calc(100% - 3px)"
            : `${leftPercent}%`;
      }
    };

    // Show tooltip
    const showTooltip = (e) => {
      clearTimeout(this.tooltipTimeout);
      tooltip.style.opacity = "1";
      tooltip.style.visibility = "visible";
      updateTooltipPosition(e);
    };

    // Hide tooltip with delay
    const hideTooltip = (delay = 0) => {
      clearTimeout(this.tooltipTimeout);
      this.tooltipTimeout = setTimeout(() => {
        tooltip.style.opacity = "0";
        tooltip.style.visibility = "hidden";
      }, delay);
    };

    // Mouse events
    this.el().addEventListener("click", seekToPosition);

    // Handle drag to seek
    const handleDrag = (e) => {
      if (this.isDragging || this.isTouchDragging) {
        seekToPosition(e);
      }
      updateTooltipPosition(e);
    };

    this.el().addEventListener("mousedown", (e) => {
      this.isDragging = true;
      seekToPosition(e);
    });

    document.addEventListener("mousemove", handleDrag);
    document.addEventListener("mouseup", () => {
      this.isDragging = false;
      if (!this.el().matches(":hover")) {
        hideTooltip();
      }
    });

    // Touch events for mobile
    this.el().addEventListener("touchstart", (e) => {
      e.preventDefault();
      this.isTouchDragging = true;
      showTooltip(e);
      seekToPosition(e);
    });

    this.el().addEventListener("touchmove", (e) => {
      e.preventDefault();
      if (this.isTouchDragging) {
        handleDrag(e);
      }
    });

    this.el().addEventListener("touchend", (e) => {
      e.preventDefault();
      this.isTouchDragging = false;
      // Hide tooltip after a delay on touch end
      hideTooltip(1000);
    });

    // Handle touch cancel
    this.el().addEventListener("touchcancel", (e) => {
      e.preventDefault();
      this.isTouchDragging = false;
      hideTooltip();
    });

    // Show tooltip on hover with position tracking
    this.el().addEventListener("mouseenter", (e) => {
      showTooltip(e);
    });

    this.el().addEventListener("mouseleave", () => {
      if (!this.isDragging) {
        hideTooltip();
      }
    });

    // Listen to player events
    this.player().on("timeupdate", updateProgress);
    this.player().on("progress", updateProgress);
    this.player().on("loadedmetadata", updateProgress);
    this.player().on("durationchange", updateProgress);
  }

  dispose() {
    // Clear tooltip timeout
    if (this.tooltipTimeout) {
      clearTimeout(this.tooltipTimeout);
      this.tooltipTimeout = null;
    }

    super.dispose();
  }
}

// Register the component
videojs.registerComponent("ProgressBar", ProgressBar);

export default ProgressBar;
