<!-- Карточка плейлиста: галерея 1-4 обложек, статистика, меню действий -->
<template>
  <div class="card-playlist">
    <NuxtLink
      :class="[
        `--${card.thumbUrls?.length > 3 ? '4' : `${card.thumbUrls?.length}`}-child`,
        {'--empty': !card.thumbUrls?.length},
      ]"
      :to="generateLink(link)"
      class="card-playlist__img-wrapper"
    >
      <UiImg
        v-for="(item, index) in card.thumbUrls"
        :key="`playlist-image-${index}`"
        :src="getCurrentImage(item, index)"
        :urls="isSingle ? item : undefined"
        :width="isSingle ? ThumbSize.Medium.split('x')[0] : ThumbSize.Small.split('x')[0]"
        :height="isSingle ? ThumbSize.Medium.split('x')[1] : ThumbSize.Small.split('x')[1]"
        :sizes="isSingle ? `(max-width: ${CSS_BREAKPOINTS.lg}px) 50vw, ${ThumbSize.Medium.split('x')[0]}px` : `${ThumbSize.Small.split('x')[0]}px`"
        :alt="card.name"
        :loading="priority ? 'eager' : 'lazy'"
        :priority="priority"
        class="card-playlist__img"
        @error="onImageError(index)"
      />
      <UiLabel
        :text="card.videosCount"
        class="card-playlist__count"
        theme="black"
      >
        <UiIcon
          name="cam"
          size="16"
        />
      </UiLabel>
    </NuxtLink>

    <!-- Кнопка живёт снаружи ссылки-обложки: button внутри a — невалидная разметка -->
    <UiFollowBtn
      v-if="showFollow"
      :following="following"
      :name="card.name"
      class="card-playlist__follow"
      size="s"
      @toggle="toggle(card.id)"
    />

    <div class="card-playlist__wrapper">
      <div class="card-playlist__wrapper-header">
        <p class="card-playlist__numbers">
          <span
            v-if="card.likes != null"
            class="card-playlist__like"
          >
            <UiIcon
              name="thumbs-up"
              size="14"
            />
            {{ $n(card.likes, 'compact') }}
          </span>
          <span
            v-if="card.views != null"
            class="card-playlist__views"
          >
            <UiIcon
              name="show"
              size="14"
            />
            {{ $n(card.views, 'compact') }}
          </span>
        </p>
        <p class="card-playlist__created">
          <UiIcon
            name="date"
            size="14"
          />
          <span class="card-playlist__updated">{{ t('library.updated') }}</span>
          <span>{{ formatDate(card.created) }}</span>
        </p>
      </div>
      <div class="card-playlist__content">
        <UiImg
          v-if="avatar"
          :src="avatar"
          :alt="card.username"
          class="card-collections-more__count _from-xs"
          width="36"
          height="36"
          sizes="36px"
        />
        <div
          v-else
          class="card-playlist__avatar --placeholder _from-xs"
        >
          {{ avatarPlaceholder }}
        </div>
        <NuxtLink
          :to="generateLink(`/playlists/${card.id}/${card.firstVideoId}`)"
          class="card-playlist__title"
        >
          <!-- У своих плейлистов приватность видна у названия: значок вместо плашки на обложке -->
          <span
            v-if="own"
            :title="visibilityTitle"
            class="card-playlist__visibility"
          >
            <UiIcon
              :name="PLAYLIST_TYPE_ICON[card.playlistType]"
              size="14"
            />
          </span>
          <span class="card-playlist__name">{{ card.name }}</span>
          <span
            v-if="card.newCount"
            class="card-playlist__badge"
          >{{ t('library.new_count', { count: card.newCount }) }}</span>
        </NuxtLink>
        <p class="card-playlist__user">
          {{ card.username }}
        </p>
        <div
          v-if="!noActions"
          class="card-playlist__content-wrapper"
        >
          <UiDropdown
            ref="dropdownRef"
            right
            use-v-if
            class="card-playlist__dropdown"
          >
            <template #trigger>
              <button
                class="card-playlist__dots"
                type="button"
              >
                <UiIcon
                  name="dots-vertical"
                  size="18"
                />
              </button>
            </template>
            <template #header>
              <CardPlaylistMini
                :card="card"
                class="card-playlist__preview _to-sm"
              />
            </template>
            <template #items="className">
              <template v-if="own">
                <button
                  :class="className"
                  type="button"
                  @click="openPlaylistEdit(PlaylistStep.Edit, false, card)"
                >
                  <UiIcon
                    name="edit"
                    size="16"
                  />
                  {{ t('playlist.edit') }}
                </button>
                <button
                  :class="[className, 'card-playlist__delete']"
                  type="button"
                  @click="openPlaylistEdit(PlaylistStep.Delete, false, card)"
                >
                  <UiIcon
                    name="trash-bin"
                    size="16"
                  />
                  {{ t('playlist.delete') }}
                </button>
              </template>
              <template v-else>
                <button
                  :class="className"
                  type="button"
                  @click="toggleFollow(card.id, card.name)"
                >
                  <UiIcon
                    :name="shownFollowing ? 'minus' : 'plus'"
                    size="16"
                  />
                  {{ followLabel }}
                </button>
                <button
                  :class="className"
                  type="button"
                  @click="emit('share', card)"
                >
                  <UiIcon
                    name="share"
                    size="16"
                  />
                  {{ t('share') }}
                </button>
                <button
                  :class="className"
                  type="button"
                  @click="onReport"
                >
                  <UiIcon
                    name="flag"
                    size="16"
                  />
                  {{ t('report') }}
                </button>
              </template>
            </template>
          </UiDropdown>
        </div>
      </div>
      <p
        v-if="card.searchTags && card.searchTags?.length > 0"
        class="card-playlist__tags _truncate"
      >
        {{ card.searchTags.join(' · ')}}
      </p>
    </div>
  </div>
</template>

<script setup lang="ts">
import { formatDate, PLAYLIST_TYPE_ICON, PlaylistStep, PlaylistType, ThumbSize } from '../../runtime';
import type { IPlaylistCard, IProfileData, IThumbUrls } from '../../types';
import { AuthorizationApiService } from '../../services/api/authorization.service';
import { CSS_BREAKPOINTS } from '../../config/css-breakpoints';

const props = defineProps<{
  card: IPlaylistCard
  topPlaylists?: boolean
  /** Без меню «три точки» — вместе с ним уходят подписка, share и report */
  noActions?: boolean
  /** Кнопка подписки поверх обложки — список подписок в библиотеке */
  showFollow?: boolean
  /** Свой плейлист: приватность значком у названия, в меню — правка и удаление вместо подписки */
  own?: boolean
  priority?: boolean
}>();

const emit = defineEmits<{
  (e: 'share', card: IPlaylistCard): void
}>();

const { t } = useI18n();

const { generateLink } = useGenerateLink();

const { openPlaylistReportPopup } = useReportPopup();

const dropdownRef = ref();

function onReport() {
  openPlaylistReportPopup(props.card, () => dropdownRef.value?.openDropdown());
}

const userProfileData = computed(() => useState<IProfileData>('profileData').value);

const { isAuthorized } = useUser(AuthorizationApiService);

const { isFollowing, toggleFollow, toggle } = usePlaylistFollow();

const { openPlaylistEdit } = usePlaylistEdit();

const isPrivate = computed(() => props.card.playlistType === PlaylistType.Private);

const visibilityTitle = computed(() => isPrivate.value
  ? t('playlist.private_playlist')
  : t('playlist.public_playlist'));

const following = computed(() => isFollowing(props.card.id));

// Тем же кликом, что переключает подписку, меню закрывается. Если менять надпись сразу, она
// дёргается прямо во время анимации закрытия, поэтому в меню живёт снапшот состояния — он
// догоняет реальное только к следующему открытию, когда пункт всё равно перерисовывается с нуля.
const shownFollowing = ref(following.value);

const followLabel = computed(() => shownFollowing.value
  ? t('unfollow')
  : t('follow'));

watch(() => dropdownRef.value?.open, (isOpen) => {
  if (isOpen) shownFollowing.value = following.value;
});

const avatar = computed(() => {
  if (isAuthorized.value && props.topPlaylists && userProfileData.value?.avatar) {
    return userProfileData.value.avatar;
  }
  return null;
});
const placeholderImage = '/img/placeholder.webp';

const imageErrors = ref<Record<number, boolean>>({});

function onImageError(index: number) {
  imageErrors.value[ index ] = true;
}

const isSingle = computed(() => (props.card.thumbUrls?.length || 0) <= 1);

function getCurrentImage(item: IThumbUrls, index: number) {
  if (imageErrors.value[ index ]) return placeholderImage;
  if (isSingle.value) return undefined;
  return item?.webp?.[ThumbSize.Small] || placeholderImage;
}

const link = computed(() => `/playlists/${props.card.id}/${props.card.firstVideoId}`);

const avatarPlaceholder = computed(() => props.card.username.charAt(0));
</script>

<style lang="scss">
// Ниже этой ширины в мета-строку не влезает «Updated» рядом с лайками, просмотрами и датой
$updated-word-width: 240px;

.card-playlist {
  position: relative;
  display: grid;
  width: 100%;
  container-type: inline-size;
  align-items: start;
  align-content: start;
  border-radius: $radius-xl;
  background-color: $playlist-card-bg;
  border: 1px solid $playlist-card-border;

  @include hover(border-color, box-shadow) {
    border-color: $playlist-card-border--hover;
    box-shadow: $card-ring-shadow--hover;
  }
}

.card-playlist__img-wrapper {
  position: relative;
  aspect-ratio: 16/9;
  display: grid;
  border-radius: $radius-xl $radius-xl 0 0;
  overflow: hidden;
}

.--2-child {
  grid-template-columns: 1fr 1fr;
}

.--4-child,
.--3-child {
  grid-template-rows: 1fr 1fr;
  grid-template-columns: 1fr 1fr;
}

.--3-child .card-playlist__img:first-child {
  grid-column: 1;
  grid-row: 1/3;
}

.--4-child .card-playlist__img:is(:first-child, :nth-child(3)),
.--3-child .card-playlist__img:first-child,
.--2-child .card-playlist__img:first-child {
  border-right: 2px solid $playlist-card-img-border;
}

.--4-child .card-playlist__img:is(:first-child, :nth-child(2)),
.--3-child .card-playlist__img:nth-child(2) {
  border-bottom: 2px solid $playlist-card-img-border;
}

.card-playlist__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  aspect-ratio: 16/9;
}

.card-playlist__wrapper {
  display: grid;
  align-items: center;
  padding: 12px;
}

.card-playlist__wrapper-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  column-gap: 24px;
  margin-bottom: 8px;
}

.card-playlist__wrapper.--top {
  grid-template-columns: 1fr auto auto;
}

.card-playlist__dots {
  padding: 2px;

  @include from-br(sm) {
    position: relative;
    transition: var(--transition) opacity;
  }
}

.card-playlist__preview {
  padding: 16px 32px 16px 16px;
  border-bottom: 1px solid $playlist-card-preview-border;
}

.card-playlist__title {
  @include font-sm;

  display: flex;
  align-items: center;
  column-gap: 6px;
  max-width: 100%;
  color: $playlist-card-title;
  font-weight: 500;
  min-width: 0;

  @include hover(color) {
    color: $playlist-card-title--hover;
  }
}

/* Обрезается название, а бейдж рядом остаётся целым */
.card-playlist__name {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.card-playlist__user {
  @include font-xs;

  grid-row: 2;
  margin-top: 8px;
  color: $playlist-card-user;
  max-width: 100%;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
}

.card-playlist__type,
.card-playlist__user {
  display: flex;
  align-items: center;
  column-gap: 4px;

  @include from-br(sm) {
    color: $playlist-card-type;
  }
}

.card-playlist__type {
  text-transform: capitalize;
}

.card-playlist__avatar {
  $size: 36px;

  grid-column: 1;
  width: $size;
  height: $size;
  border-radius: 50%;
  grid-row: 1/3;
}

.card-playlist__count {
  position: absolute;
  top: 8px;
  left: 8px;
}

.card-playlist__img-wrapper.--empty {
  display: grid;
  place-content: center;
  background: linear-gradient(to bottom right in oklab, $playlist-card-empty-gradient-from, $playlist-card-empty-gradient-to);
  color: $playlist-card-empty-text;
}

.card-playlist__visibility {
  display: grid;
  flex-shrink: 0;
  color: $playlist-card-visibility-icon;
}

/* Дропдаун красит свои пункты и иконки сам, поэтому селектор адресный — иначе «удалить» не красное */
.ui-dropdown__menu-items > .card-playlist__delete.ui-dropdown__item {
  color: $playlist-card-delete-text;
}

.ui-dropdown__menu-items > .card-playlist__delete.ui-dropdown__item .ui-icon {
  color: inherit;
}

.card-playlist__follow {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: $z-index-plus;
}

.card-playlist__tags {
  @include font-xs;

  --line-clamp: 1;

  color: $playlist-card-tags;
  padding-top: 8px;
  margin-top: 8px;
  border-top: 1px solid $playlist-card-tags-border;
}

.card-playlist__numbers {
  display: flex;
  column-gap: 12px;
  align-items: center;
  flex-wrap: nowrap;
}

.card-playlist__like,
.card-playlist__created {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  column-gap: 4px;
}

.card-playlist__numbers {
  @include font-xs;

  color: $playlist-card-meta;
}

.card-playlist__created {
  @include font-3xs;

  color: $playlist-card-meta;
}

@include to-cq($updated-word-width) {
  .card-playlist__updated {
    display: none;
  }
}

.card-playlist__avatar.--placeholder {
  @include font-xs;

  display: grid;
  place-content: center;
  border-radius: $radius-full;
  font-weight: 700;
  color: $playlist-card-placeholder-text;
  text-transform: uppercase;
  background-color: $playlist-card-placeholder-bg;
}

.card-playlist__content {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 12px;
  align-items: start;
}

.card-playlist__content-wrapper {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  column-gap: 6px;
  grid-row: 1/3;
  grid-column: 3;
}

.card-playlist__views {
  @include font-xs;

  color: $playlist-card-meta;
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  column-gap: 4px;
}

.card-playlist__badge {
  @include font-3xs;

  display: grid;
  place-content: center;
  flex-shrink: 0;
  height: 20px;
  padding-inline: 6px;
  font-weight: 700;
  white-space: nowrap;
  color: $card-new-badge-text;
  background-color: $card-new-badge-bg;
  border-radius: $radius-full;
}

.card-playlist__dropdown {
  color: $playlist-card-dropdown-icon;

  @include hover(color) {
    color: $playlist-card-dropdown-icon--hover;
  }
}
</style>
