<!-- Внешнее меню плеера (menus: 'external-mobile'): плеер на мобиле не рисует свои
     попапы, а эмитит menurequest с готовой моделью (настройки / тайм-коды / ⋯) и живыми
     колбэками, которые сами применяют выбор. Рендерим её в нашем ui-popup (--sheet).
     Дрилл «Настройки → Скорость/Качество» — через стек drill с кнопкой «назад». -->
<template>
  <transition mode="out-in">
    <UiPopup
      v-if="open && request"
      v-model="open"
      sheet
      :back="!!drill"
      class="player-menu"
      @back="drill = null"
    >
      <template #title>
        {{ drill?.label ?? request.title }}
      </template>

      <!-- Дрилл: опции одной настройки (скорость / качество / субтитры) -->
      <ul
        v-if="drill"
        class="player-menu__options"
      >
        <li
          v-for="option in drill.options"
          :key="option.value"
        >
          <button
            :class="{ '--active': option.active }"
            class="player-menu__option"
            type="button"
            @click="pick(drill.select, option.value)"
          >
            {{ option.label }}
          </button>
        </li>
      </ul>

      <!-- Шестерёнка: тоглы + строки-дриллы -->
      <ul
        v-else-if="request.kind === 'settings'"
        class="player-menu__rows"
      >
        <li
          v-for="entry in request.entries"
          :key="entry.key"
          class="player-menu__row"
        >
          <div
            v-if="entry.toggle"
            class="player-menu__toggle-row"
          >
            <span class="player-menu__label">{{ entry.label }}</span>
            <UiToggle
              :model-value="toggleOverrides[entry.key] ?? entry.toggle.value"
              @update:model-value="setToggle(entry, !!$event)"
            />
          </div>
          <button
            v-else-if="entry.options && entry.select"
            class="player-menu__row-btn"
            type="button"
            @click="drill = { label: entry.label, options: entry.options, select: entry.select }"
          >
            <span class="player-menu__label">{{ entry.label }}</span>
            <span class="player-menu__value">
              {{ entry.value }}
              <UiIcon
                name="chevron-right"
                size="16"
              />
            </span>
          </button>
          <div
            v-else
            class="player-menu__toggle-row"
          >
            <span class="player-menu__label">{{ entry.label }}</span>
            <span class="player-menu__value">{{ entry.value }}</span>
          </div>
        </li>
      </ul>

      <!-- Тайм-коды: аккордеон типов сцен -->
      <ul
        v-else-if="request.kind === 'sceneTypes'"
        class="player-menu__groups"
      >
        <li
          v-for="group in request.groups"
          :key="group.id"
        >
          <details
            :open="group.active"
            class="player-menu__group"
            @toggle="onGroupToggle($event, group)"
          >
            <summary class="player-menu__summary">
              <span
                v-if="iconSvg(group.icon)"
                class="player-menu__summary-icon"
                v-html="iconSvg(group.icon)"
              />
              <span class="player-menu__summary-title">{{ group.title }}</span>
              <UiIcon
                name="chevron-down"
                size="20"
                class="player-menu__summary-arrow"
              />
            </summary>
            <ul class="player-menu__scenes">
              <li
                v-for="scene in group.scenes"
                :key="scene.start"
              >
                <button
                  :class="{ '--current': scene.current }"
                  class="player-menu__scene"
                  type="button"
                  @click="selectScene(group.id, scene.start)"
                >
                  <span class="player-menu__scene-label">{{ scene.label }}</span>
                  <span class="player-menu__scene-time">{{ scene.time }}</span>
                </button>
              </li>
            </ul>
          </details>
        </li>
      </ul>

      <!-- ⋯ и одиночные меню (скорость/качество/субтитры, если вынесены кнопками) -->
      <template v-else-if="request.kind === 'menu'">
        <section
          v-for="(section, index) in request.sections"
          :key="index"
          class="player-menu__section"
        >
          <h3
            v-if="section.title"
            class="player-menu__section-title"
          >
            {{ section.title }}
          </h3>
          <ul class="player-menu__options">
            <li
              v-for="item in section.items"
              :key="item.value"
            >
              <button
                :class="{ '--active': item.active }"
                class="player-menu__option"
                type="button"
                @click="pick(section.select, item.value)"
              >
                {{ item.label }}
              </button>
            </li>
          </ul>
        </section>
      </template>
    </UiPopup>
  </transition>
</template>

<script setup lang="ts">
import type { MenuRequestPayload } from 'itube-modern-player';

type SceneGroup = Extract<MenuRequestPayload, { kind: 'sceneTypes' }>['groups'][number];
type SettingsEntry = Extract<MenuRequestPayload, { kind: 'settings' }>['entries'][number];

// Иконку типа сцен рендерим только когда это сырой svg (мы отдаём именно {svg} из core.vue).
function iconSvg(icon?: SceneGroup['icon']): string | undefined {
  return icon && typeof icon === 'object' && 'svg' in icon ? icon.svg : undefined;
}

interface Drill {
  label: string
  options: NonNullable<SettingsEntry['options']>
  select: (value: string) => void
}

const props = defineProps<{
  request: MenuRequestPayload | null
}>();

const open = defineModel<boolean>('open', { required: true });

// Стек дрилла «Настройки → опция». Сбрасываем на каждый новый запрос (плеер эмитит
// menurequest на каждое нажатие кнопки — открываем корень меню заново).
const drill = shallowRef<Drill | null>(null);

// Плеер отдаёт toggle.value разовым снимком и НЕ переэмитит menurequest на
// переключение — держим локальный оверрайд, чтобы тумблер сразу двигался.
// Сбрасываем на каждый новый запрос (свежие значения из плеера).
const toggleOverrides = reactive<Record<string, boolean>>({});

watch(() => props.request, () => {
  drill.value = null;
  for (const key in toggleOverrides) delete toggleOverrides[key];
});

function setToggle(entry: SettingsEntry, on: boolean): void {
  if (!entry.toggle) return;
  entry.toggle.set(on);
  toggleOverrides[entry.key] = on;
}

// select у плеера сам делает setRate/seek/play и шлёт свои события — руками ничего не
// дёргаем, просто закрываем шторку.
function pick(select: (value: string) => void, value: string): void {
  select(value);
  open.value = false;
}

function selectScene(groupId: string, start: number): void {
  if (props.request?.kind !== 'sceneTypes') return;
  props.request.select(groupId, start);
  open.value = false;
}

// Раскрытие группы = смена активного типа сцен (native ведёт себя так же).
function onGroupToggle(event: Event, group: SceneGroup): void {
  if (props.request?.kind !== 'sceneTypes') return;
  if ((event.target as HTMLDetailsElement).open && !group.active) {
    props.request.activate(group.id);
  }
}
</script>

<style lang="scss">
// Фон шторки (bg-zinc-900); шапка/бордеры ui-popup уже совпадают с v0 (#0d0d0d, zinc-800).
.player-menu .ui-popup__wrapper,
.player-menu .ui-popup__content {
  background-color: $player-menu-bg;
}

// Вертикальный воздух списка + safe-area снизу (py-2 pb-[env(safe-area-inset-bottom)] в v0).
// Сильный селектор — перебиваем padding:0 у .ui-popup--sheet на мобиле.
.player-menu.ui-popup[open].--sheet .ui-popup__content {
  padding: 8px 0 calc(8px + env(safe-area-inset-bottom, 0px));
}

.player-menu__rows,
.player-menu__groups,
.player-menu__options {
  display: flex;
  flex-direction: column;
}

.player-menu__row + .player-menu__row {
  border-top: 1px solid $player-menu-row-border;
}

.player-menu__toggle-row,
.player-menu__row-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: 100%;
  min-height: 52px;
  padding: 8px 20px;
}

.player-menu__row-btn {
  @include hover(background-color) {
    background-color: $player-menu-row-bg--hover;
  }
}

// Без слота лейбл ui-toggle нулевой ширины → абсолютный трек уезжает за padding шторки.
// Резервируем ширину контрола и перекрашиваем вкл-состояние в indigo (в v0 bg-indigo-500).
.player-menu .ui-toggle {
  flex-shrink: 0;
  width: 36px;
  height: 20px;
}

.player-menu .ui-toggle.ui-toggle--checked::before {
  background: $player-menu-toggle-bg--active;
}

.player-menu__label {
  @include font-md;

  color: $player-menu-row-text;
}

.player-menu__value {
  @include font-md;

  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: $player-menu-value;
}

.player-menu__option {
  @include font-md;

  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 48px;
  padding: 8px 20px;
  color: $player-menu-option-text;

  @include hover(background-color) {
    background-color: $player-menu-option-bg--hover;
  }
}

.player-menu__option.--active {
  background-color: $player-menu-option-bg--active;
  color: $player-menu-option-text--active;
  font-weight: 500;
}

.player-menu__option.--active::before {
  content: '';
  position: absolute;
  inset-block: 0;
  left: 0;
  width: 2px;
  background-color: $player-menu-option-bar--active;
}

.player-menu__groups > li + li {
  border-top: 1px solid $player-menu-acc-border;
}

.player-menu__summary {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 8px 20px;
  color: $player-menu-acc-head-text;
  cursor: pointer;
  list-style: none;
  user-select: none;

  &::-webkit-details-marker {
    display: none;
  }

  @include hover(background-color) {
    background-color: $player-menu-acc-head-bg--hover;
  }
}

.player-menu__group[open] .player-menu__summary {
  color: $player-menu-acc-head-text--open;
}

.player-menu__summary-icon {
  display: grid;
  place-content: center;
  flex-shrink: 0;

  svg {
    width: 16px;
    height: 16px;
  }
}

.player-menu__summary-title {
  @include font-md;

  flex: 1;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.player-menu__summary-arrow {
  margin-right: 12px;
  flex-shrink: 0;
  color: $player-menu-icon;
  transition: transform var(--transition), color var(--transition);
}

.player-menu__group[open] .player-menu__summary-arrow {
  color: $player-menu-icon--open;
  transform: rotate(180deg);
}

.player-menu__scenes {
  padding-bottom: 4px;
}

.player-menu__scene {
  @include font-md;

  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: 48px;
  padding: 6px 20px 6px 56px;
  color: $player-menu-scene-text;

  @include hover(background-color) {
    background-color: $player-menu-scene-bg--hover;
  }
}

.player-menu__scene.--current {
  background-color: $player-menu-scene-bg--current;
}

.player-menu__scene.--current::before {
  content: '';
  position: absolute;
  inset-block: 0;
  left: 0;
  width: 2px;
  background-color: $player-menu-scene-bar--current;
}

.player-menu__scene-label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left;
}

.player-menu__scene.--current .player-menu__scene-label {
  font-weight: 500;
  color: $player-menu-scene-text--current;
}

.player-menu__scene-time {
  @include font-xs;

  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
  color: $player-menu-scene-time;
}

.player-menu__scene.--current .player-menu__scene-time {
  color: $player-menu-scene-time--current;
}

.player-menu__section + .player-menu__section {
  border-top: 1px solid $player-menu-row-border;
}

.player-menu__section-title {
  @include font-xs;

  padding: 12px 20px 4px;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
  color: $player-menu-section-title;
}
</style>
