import { computed, signal, effect, camelToKebabCase, Host } from '../../chunks/vidstack-BNpgCJJ1.js';
import { DefaultLayout, useDefaultLayoutContext, DefaultPlayButton, DefaultAnnouncer, DefaultCaptions, DefaultControlsSpacer, DefaultCaptionButton, DefaultDownloadButton, DefaultVolumePopup, DefaultTimeSlider, DefaultSeekButton, DefaultTimeInfo, DefaultFullscreenButton, DefaultTitle, DefaultPIPButton, DefaultChaptersMenu, DefaultSettingsMenu, DefaultEpisodeButton, setLayoutName, createMenuContainer, DefaultLayoutIconsLoader } from '../../chunks/vidstack-Ko2EJadT.js';
import { useMediaContext, useMediaState } from '../../chunks/vidstack-tt3O1zL6.js';
import { $signal, SlotManager } from '../../chunks/vidstack-zfCm-GM5.js';
import { LitElement } from '../../chunks/vidstack-CwTj4H1w.js';
import { html } from 'lit-html';
import { keyed } from 'lit-html/directives/keyed.js';
import { createSlot } from '../../chunks/vidstack-DB9WDRL5.js';
import '../../chunks/vidstack-BP49Gz0m.js';
import '../../chunks/vidstack-BTM4ERc7.js';
import 'lit-html/directives/if-defined.js';
import 'lit-html/directives/ref.js';
import '../../chunks/vidstack-KShKSmYu.js';
import '../../chunks/vidstack-wTTCvdqe.js';
import 'lit-html/directives/unsafe-svg.js';
import 'lit-html/async-directive.js';
import '@floating-ui/dom';

class DefaultVideoLayout extends DefaultLayout {
  static props = {
    ...super.props,
    when: ({ viewType }) => viewType === "video",
    smallWhen: ({ width, height }) => width < 576 || height < 380
  };
}

function DefaultKeyboardDisplay() {
  return $signal(() => {
    const media = useMediaContext(), { noKeyboardAnimations, userPrefersKeyboardAnimations } = useDefaultLayoutContext(), $disabled = computed(() => noKeyboardAnimations() || !userPrefersKeyboardAnimations());
    if ($disabled()) {
      return null;
    }
    const visible = signal(false), { lastKeyboardAction } = media.$state;
    effect(() => {
      visible.set(!!lastKeyboardAction());
      const id = setTimeout(() => visible.set(false), 500);
      return () => {
        visible.set(false);
        window.clearTimeout(id);
      };
    });
    const $actionDataAttr = computed(() => {
      const action = lastKeyboardAction()?.action;
      return action && visible() ? camelToKebabCase(action) : null;
    });
    const $classList = computed(() => `vds-kb-action${!visible() ? " hidden" : ""}`), $text = computed(getText), $iconSlot = computed(() => {
      const name = getIconName();
      return name ? createSlot(name) : null;
    });
    function Icon() {
      const $slot = $iconSlot();
      if (!$slot) return null;
      return html`
        <div class="vds-kb-bezel">
          <div class="vds-kb-icon">${$slot}</div>
        </div>
      `;
    }
    return html`
      <div class=${$signal($classList)} data-action=${$signal($actionDataAttr)}>
        <div class="vds-kb-text-wrapper">
          <div class="vds-kb-text">${$signal($text)}</div>
        </div>
        ${$signal(() => keyed(lastKeyboardAction(), Icon()))}
      </div>
    `;
  });
}
function getText() {
  const { $state } = useMediaContext(), action = $state.lastKeyboardAction()?.action, audioGain = $state.audioGain() ?? 1;
  switch (action) {
    case "toggleMuted":
      return $state.muted() ? "0%" : getVolumeText($state.volume(), audioGain);
    case "volumeUp":
    case "volumeDown":
      return getVolumeText($state.volume(), audioGain);
    default:
      return "";
  }
}
function getVolumeText(volume, gain) {
  return `${Math.round(volume * gain * 100)}%`;
}
function getIconName() {
  const { $state } = useMediaContext(), action = $state.lastKeyboardAction()?.action;
  switch (action) {
    case "togglePaused":
      return !$state.paused() ? "kb-play-icon" : "kb-pause-icon";
    case "toggleMuted":
      return $state.muted() || $state.volume() === 0 ? "kb-mute-icon" : $state.volume() >= 0.5 ? "kb-volume-up-icon" : "kb-volume-down-icon";
    case "toggleFullscreen":
      return `kb-fs-${$state.fullscreen() ? "enter" : "exit"}-icon`;
    case "togglePictureInPicture":
      return `kb-pip-${$state.pictureInPicture() ? "enter" : "exit"}-icon`;
    case "toggleCaptions":
      return $state.hasCaptions() ? `kb-cc-${$state.textTrack() ? "on" : "off"}-icon` : null;
    case "volumeUp":
      return "kb-volume-up-icon";
    case "volumeDown":
      return "kb-volume-down-icon";
    case "seekForward":
      return "kb-seek-forward-icon";
    case "seekBackward":
      return "kb-seek-backward-icon";
    default:
      return null;
  }
}

function DefaultVideoLayoutLarge() {
  const { episodes, smallWhen: smWhen } = useDefaultLayoutContext(), { fullscreen } = useMediaState(), $episodesOpen = signal(false);
  effect(() => {
    if (!fullscreen()) $episodesOpen.set(false);
  });
  function onEpisodesToggle() {
    if (!fullscreen() && !smWhen() || !episodes()?.length) return;
    $episodesOpen.set(!$episodesOpen());
  }
  function onEpisodesClose() {
    $episodesOpen.set(false);
  }
  return [
    DefaultAnnouncer(),
    DefaultVideoGestures(),
    DefaultBufferingIndicator(),
    DefaultKeyboardDisplay(),
    DefaultCaptions(),
    html`<div class="vds-scrim"></div>`,
    html`
      <media-controls class="vds-controls" @vds-episodes-open=${onEpisodesToggle}>
        ${[
      DefaultControlsGroupTop(),
      DefaultControlsSpacer(),
      html`
            <media-controls-group class="vds-controls-group">
              ${DefaultTimeSlider()}
            </media-controls-group>
          `,
      html`
            <media-controls-group class="vds-controls-group vds-controls-group-bottom">
              ${[
        DefaultSeekButton({ backward: true, tooltip: "top" }),
        DefaultPlayButton({ tooltip: "top start" }),
        DefaultSeekButton({ backward: false, tooltip: "top" }),
        DefaultVolumePopup({ orientation: "horizontal", tooltip: "top" }),
        DefaultTimeInfo(),
        DefaultTitle(),
        DefaultControlsSpacer(),
        $signal(
          () => (fullscreen() || smWhen()) && episodes()?.length ? DefaultEpisodeButton({ tooltip: "top" }) : null
        ),
        DefaultCaptionButton({ tooltip: "top" }),
        DefaultBottomMenuGroup(),
        DefaultDownloadButton(),
        DefaultPIPButton(),
        DefaultFullscreenButton({ tooltip: "top end" })
      ]}
            </media-controls-group>
          `
    ]}
      </media-controls>
    `,
    DefaultEpisodesSidebar($episodesOpen, onEpisodesClose)
  ];
}
function DefaultBottomMenuGroup() {
  return $signal(() => {
    const { menuGroup } = useDefaultLayoutContext();
    return menuGroup() === "bottom" ? DefaultVideoMenus() : null;
  });
}
function DefaultControlsGroupTop() {
  return html`
    <media-controls-group class="vds-controls-group">
      ${$signal(() => {
    const { menuGroup } = useDefaultLayoutContext();
    return menuGroup() === "top" ? [DefaultControlsSpacer(), DefaultVideoMenus()] : null;
  })}
    </media-controls-group>
  `;
}
function DefaultVideoLayoutSmall() {
  const { episodes, smallWhen: smWhen } = useDefaultLayoutContext(), { fullscreen } = useMediaState(), $episodesOpen = signal(false);
  effect(() => {
    if (!fullscreen()) $episodesOpen.set(false);
  });
  function onEpisodesToggle() {
    if (!fullscreen() && !smWhen() || !episodes()?.length) return;
    $episodesOpen.set(!$episodesOpen());
  }
  function onEpisodesClose() {
    $episodesOpen.set(false);
  }
  return [
    DefaultAnnouncer(),
    DefaultVideoGestures(),
    DefaultBufferingIndicator(),
    DefaultCaptions(),
    DefaultKeyboardDisplay(),
    html`<div class="vds-scrim"></div>`,
    html`
      <media-controls class="vds-controls" @vds-episodes-open=${onEpisodesToggle}>
        <media-controls-group class="vds-controls-group">
          ${[
      DefaultControlsSpacer(),
      DefaultCaptionButton({ tooltip: "bottom" }),
      DefaultDownloadButton(),
      DefaultVideoMenus(),
      DefaultVolumePopup({ orientation: "vertical", tooltip: "bottom end" })
    ]}
        </media-controls-group>

        ${DefaultControlsSpacer()}

        <media-controls-group class="vds-controls-group">
          ${DefaultTimeSlider()}
        </media-controls-group>

        <media-controls-group class="vds-controls-group vds-controls-group-bottom">
          ${[
      DefaultSeekButton({ backward: true, tooltip: "top" }),
      DefaultPlayButton({ tooltip: "top" }),
      DefaultSeekButton({ backward: false, tooltip: "top" }),
      DefaultTimeInfo(),
      DefaultControlsSpacer(),
      $signal(
        () => (fullscreen() || smWhen()) && episodes()?.length ? DefaultEpisodeButton({ tooltip: "top" }) : null
      ),
      DefaultFullscreenButton({ tooltip: "top end" })
    ]}
        </media-controls-group>
      </media-controls>
    `,
    StartDuration(),
    DefaultEpisodesSidebar($episodesOpen, onEpisodesClose)
  ];
}
function DefaultVideoLoadLayout() {
  return html`
    <div class="vds-load-container">
      ${[DefaultBufferingIndicator(), DefaultPlayButton({ tooltip: "top" })]}
    </div>
  `;
}
function StartDuration() {
  return $signal(() => {
    const { duration } = useMediaState();
    if (duration() === 0) return null;
    return html`
      <div class="vds-start-duration">
        <media-time class="vds-time" type="duration"></media-time>
      </div>
    `;
  });
}
function DefaultBufferingIndicator() {
  return html`
    <div class="vds-buffering-indicator">
      <media-spinner class="vds-buffering-spinner"></media-spinner>
    </div>
  `;
}
function formatMinutesLeftLabel(secondsLeft) {
  if (secondsLeft <= 0) return null;
  if (secondsLeft < 60) return "<1m left";
  return `${Math.floor(secondsLeft / 60)}m left`;
}
function DefaultEpisodesSidebar($open, onClose) {
  const { episodes, episodesTitle, smallWhen: smWhen } = useDefaultLayoutContext(), { fullscreen, currentTime, duration } = useMediaState();
  return $signal(() => {
    const list = episodes() ?? [];
    if (!fullscreen() && !smWhen() || !list.length) return null;
    const ct = currentTime(), dur = duration();
    return html`
      <div
        class="vds-episodes-backdrop"
        data-open=${$open() ? "true" : "false"}
        @pointerup=${(event) => {
      if (event.target === event.currentTarget) onClose();
    }}
      >
        <aside
          class="vds-episodes-panel"
          data-open=${$open() ? "true" : "false"}
          @keydown=${(event) => {
      if (event.key === "Escape") onClose();
    }}
        >
          <header class="vds-episodes-panel-header">
            <h3 class="vds-episodes-panel-title">${episodesTitle()}</h3>
            <button
              type="button"
              class="vds-episodes-close-btn"
              aria-label="Close episodes"
              @pointerup=${(event) => {
      event.stopPropagation();
      onClose();
    }}
            >
              <span aria-hidden="true">✕</span>
            </button>
          </header>
          <div class="vds-episodes-list" role="list">
            ${list.map((episode, index) => {
      const episodeName = episode.episodeTitle || `Episode ${episode.episodeNumber ?? index + 1}`, seasonEpLabel = episode.seasonNumber != null && episode.episodeNumber != null ? `S${String(episode.seasonNumber).padStart(2, "0")} \xB7 E${String(
        episode.episodeNumber
      ).padStart(2, "0")}` : episodeName, isActive = episode.isActive === true;
      let runtimeText = null;
      if (isActive && dur > 0) {
        const secsLeft = Math.max(0, dur - ct);
        runtimeText = formatMinutesLeftLabel(secsLeft);
      } else if (episode.timeLeft != null && episode.timeLeft > 0) {
        runtimeText = `${episode.timeLeft}m left`;
      } else if (Number.isFinite(episode.runtime) && (episode.runtime ?? 0) > 0) {
        runtimeText = `${episode.runtime}m`;
      }
      let progressPct = 0;
      if (isActive && dur > 0) {
        progressPct = Math.min(100, ct / dur * 100);
      } else if (episode.progressPercent != null && episode.progressPercent > 0) {
        progressPct = Math.min(100, episode.progressPercent);
      }
      const showSubtitle = !!episode.episodeTitle && episode.episodeTitle.trim() !== "" && episode.episodeTitle !== episode.title;
      const onEpisodeSelect = (event) => {
        event.stopPropagation();
        if (isActive) return;
        event.currentTarget?.dispatchEvent(
          new CustomEvent("vds-episode-select", {
            bubbles: true,
            composed: true,
            detail: { episode, index }
          })
        );
        onClose();
      };
      return html`
                <article
                  class="vds-episode-item"
                  data-active=${isActive ? "true" : "false"}
                  aria-current=${isActive ? "true" : void 0}
                  role="button"
                  tabindex="0"
                  aria-label=${episode.title || episodeName}
                  @pointerup=${onEpisodeSelect}
                  @keydown=${(event) => {
        if (event.key === "Enter" || event.key === " ") onEpisodeSelect(event);
      }}
                >
                  <div class="vds-episode-thumb-wrap">
                    ${episode.thumbnail ? html`
                          <img
                            class="vds-episode-thumb"
                            src=${episode.thumbnail}
                            alt=${episode.title || episodeName}
                            loading="lazy"
                            decoding="async"
                          />
                        ` : html`<div class="vds-episode-thumb vds-episode-thumb-placeholder"></div>`}
                    ${progressPct > 0 ? html`
                          <div class="vds-episode-progress-track" aria-hidden="true">
                            <div
                              class="vds-episode-progress-fill"
                              style=${`width: ${progressPct}%;`}
                            ></div>
                          </div>
                        ` : null}
                  </div>
                  <div class="vds-episode-body">
                    <div class="vds-episode-meta-row">
                      <div class="vds-episode-meta-primary">
                        ${isActive ? html`<span class="vds-episode-now-chip">Playing</span>` : null}
                        <span class="vds-episode-label">${seasonEpLabel}</span>
                      </div>
                      ${runtimeText ? html`<span class="vds-episode-runtime">${runtimeText}</span>` : null}
                    </div>
                    <h4 class="vds-episode-title" title=${episode.title || ""}>
                      ${episode.title || "-"}
                    </h4>
                    ${showSubtitle ? html`<p class="vds-episode-subtitle" title=${episode.episodeTitle}>
                          ${episode.episodeTitle}
                        </p>` : null}
                    ${episode.overview ? html`<p class="vds-episode-desc" title=${episode.overview}>
                          ${episode.overview}
                        </p>` : null}
                  </div>
                </article>
              `;
    })}
          </div>
        </aside>
      </div>
    `;
  });
}
function DefaultVideoMenus() {
  const { menuGroup, smallWhen: smWhen } = useDefaultLayoutContext(), $side = () => menuGroup() === "top" || smWhen() ? "bottom" : "top", $tooltip = computed(() => `${$side()} ${menuGroup() === "top" ? "end" : "center"}`), $placement = computed(() => `${$side()} end`);
  return [
    DefaultChaptersMenu({ tooltip: $tooltip, placement: $placement, portal: true }),
    DefaultSettingsMenu({ tooltip: $tooltip, placement: $placement, portal: true })
  ];
}
function DefaultVideoGestures() {
  return $signal(() => {
    const { noGestures } = useDefaultLayoutContext();
    if (noGestures()) return null;
    return html`
      <div class="vds-gestures">
        <media-gesture class="vds-gesture" event="pointerup" action="toggle:paused"></media-gesture>
        <media-gesture
          class="vds-gesture"
          event="pointerup"
          action="toggle:controls"
        ></media-gesture>
        <media-gesture
          class="vds-gesture"
          event="dblpointerup"
          action="toggle:fullscreen"
        ></media-gesture>
        <media-gesture class="vds-gesture" event="dblpointerup" action="seek:-10"></media-gesture>
        <media-gesture class="vds-gesture" event="dblpointerup" action="seek:10"></media-gesture>
      </div>
    `;
  });
}

class MediaVideoLayoutElement extends Host(LitElement, DefaultVideoLayout) {
  static tagName = "media-video-layout";
  static attrs = {
    smallWhen: {
      converter(value) {
        return value !== "never" && !!value;
      }
    },
    episodes: {
      converter(value) {
        if (!value) return null;
        try {
          const parsed = JSON.parse(value);
          return Array.isArray(parsed) ? parsed : null;
        } catch {
          return null;
        }
      }
    }
  };
  #media;
  onSetup() {
    this.forwardKeepAlive = false;
    this.#media = useMediaContext();
    this.classList.add("vds-video-layout");
  }
  onConnect() {
    setLayoutName("video", () => this.isMatch);
    this.#setupMenuContainer();
  }
  render() {
    return $signal(this.#render.bind(this));
  }
  #setupMenuContainer() {
    const { menuPortal } = useDefaultLayoutContext();
    effect(() => {
      if (!this.isMatch) return;
      const container = createMenuContainer(
        this,
        this.menuContainer,
        "vds-video-layout",
        () => this.isSmallLayout
      ), roots = container ? [this, container] : [this];
      const iconsManager = this.$props.customIcons() ? new SlotManager(roots) : new DefaultLayoutIconsLoader(roots);
      iconsManager.connect();
      menuPortal.set(container);
      return () => {
        container.remove();
        menuPortal.set(null);
      };
    });
  }
  #render() {
    const { load } = this.#media.$props, { canLoad, streamType, nativeControls } = this.#media.$state;
    return !nativeControls() && this.isMatch ? load() === "play" && !canLoad() ? DefaultVideoLoadLayout() : streamType() === "unknown" ? DefaultBufferingIndicator() : this.isSmallLayout ? DefaultVideoLayoutSmall() : DefaultVideoLayoutLarge() : null;
  }
}

export { MediaVideoLayoutElement };
