<script setup lang="ts">
import type { Track, Listening } from '~/types'

import { ref, reactive, watch, computed } from 'vue'
import { useStore } from '~/store'
import { clone } from 'lodash-es'
import { useI18n } from 'vue-i18n'
import { getArtistCoverUrl } from '~/utils/utils'

import axios from 'axios'

import useWebSocketHandler from '~/composables/useWebSocketHandler'
import Button from '~/components/ui/Button.vue'
import PlayButton from '~/components/audio/PlayButton.vue'
import TagsList from '~/components/tags/List.vue'
import Section from '~/components/ui/Section.vue'
import Alert from '~/components/ui/Alert.vue'
import Spacer from '~/components/ui/Spacer.vue'
import Loader from '~/components/ui/Loader.vue'
import Heading from '~/components/ui/Heading.vue'

import useErrorHandler from '~/composables/useErrorHandler'


interface Events {
  (e: 'count', count: number): void
}

interface Props {
  filters: Record<string, string | boolean>
  url: string
  isActivity?: boolean
  showCount?: boolean
  limit?: number
  itemClasses?: string
  websocketHandlers?: string[]
}

const emit = defineEmits<Events>()
const props = withDefaults(defineProps<Props>(), {
  isActivity: true,
  showCount: false,
  limit: 9,
  itemClasses: '',
  websocketHandlers: () => []
})

const store = useStore()
const { t } = useI18n()

const objects = reactive([] as Listening[])
const count = ref(0)
const nextPage = ref<string | null>(null)

const isLoading = ref(false)
const fetchData = async (url = props.url) => {
  isLoading.value = true

  const params = {
    ...clone(props.filters),
    page_size: props.limit
  }

  try {
    const response = await axios.get(url, { params })
    nextPage.value = response.data.next
    count.value = response.data.count

    const newObjects = !props.isActivity
      ? response.data.results.map((track: Track) => ({ track }))
      : response.data.results

    objects.push(...newObjects)
  } catch (error) {
    useErrorHandler(error as Error)
  }

  isLoading.value = false
}

watch(
  () => store.state.moderation.lastUpdate,
  () => fetchData(),
  { immediate: true }
)

watch(count, (to) => emit('count', to))

watch(() => props.websocketHandlers.includes('Listen'), (to) => {
  if (to) {
    useWebSocketHandler('Listen', (event) => {
      // Handle WebSocket events for "Listen"

      // Add the event to `objects` reactively
      objects.unshift(event as Listening);

      // Keep the array size within limits (e.g., remove the last item if needed)
      if (objects.length > props.limit) {
        objects.pop();
      }

      // Recompute coverUrl for the updated `objects`
      console.log('WebSocket event received:', event);
      console.log('Updated cover URL:', coverUrl.value);
    });
  }
});
</script>

<template>
<!-- TODO: Use activity.vue -->
  <h2 v-if="!!$slots.title">
    <slot name="title" />
    <span
      v-if="showCount"
      class="ui tiny circular label"
    >{{ count }}</span>
  </h2>
  <Alert
    v-if="count === 0"
    blue
    style="text-align: center;"
  >
    <i class="bi bi-music-note-list" />
    {{ t('components.audio.track.Widget.empty.noResults') }}
    <Loader v-if="isLoading" />
  </Alert>
  <template
    v-if="count > 0"
    medium-items
  >
    <div class="funkwhale activity"
      v-for="object in objects"
      :key="object.id"
      :class="['item', itemClasses]"
    >
      <div class="activity-image">
        <img
          v-if="object.track.album && object.track.album.cover"
          v-lazy="store.getters['instance/absoluteUrl'](object.track.album.cover.urls.medium_square_crop)"
          alt=""
        >
        <img
          v-else-if="object.track.cover"
          v-lazy="store.getters['instance/absoluteUrl'](object.track.cover.urls.medium_square_crop)"
          alt=""
        >
        <img
          v-else-if="object.track.artist_credit && object.track.artist_credit.length > 1"
          v-lazy="getArtistCoverUrl(object.track.artist_credit)"
          alt=""
        >
        <i
          v-else
          class="bi bi-vinyl-fill"
        />
        <!-- TODO: Add Playbutton overlay -->
      </div>
      <div class="activity-content">
          <router-link
            class="funkwhale link artist"
            :to="{name: 'library.tracks.detail', params: {id: object.track.id}}"
          >
            <Heading :h3="object.track.title" title />
          </router-link>
          <Spacer :size="2"/>
        <div
          v-if="object.track.artist_credit"
          class="funkwhale link artist"
        >
          <span
            v-for="ac in object.track.artist_credit"
            :key="ac.artist.id"
          >
            <router-link
              class="discrete link"
              :to="{ name: 'library.artists.detail', params: { id: ac.artist.id } }"
            >
              {{ ac.credit }}
            </router-link>
            <span v-if="ac.joinphrase">{{ ac.joinphrase }}</span>
          </span>
        </div>
        <TagsList
          label-classes="tiny"
          :truncate-size="20"
          :limit="2"
          :show-more="false"
          :tags="object.track.tags"
        />
        <Spacer :size="4"/>
        <div
          v-if="isActivity"
          class="extra"
        >
          <router-link
            class="funkwhale link user"
            :to="{name: 'profile.overview', params: {username: object.actor.name}}"
          >
            <span class="at symbol" />{{ object.actor.name }}
          </router-link>
          <span class="right floated"><human-date :date="object.creation_date" /></span>
        </div>
      </div>
      <play-button
        :account="object.actor"
        :dropdown-only="true"
        :track="object.track"
        square-small
      />
    </div>
  </template>
  <Loader v-if="isLoading" />
  <template v-if="nextPage">
    <Spacer :size="16"/>
    <Button
      primary
      @click="fetchData(nextPage as string)"
    >
      {{ t('components.audio.track.Widget.button.more') }}
    </Button>
  </template>
</template>


<style lang="scss" scoped>
.funkwhale {
  &.activity {
    padding-top: 14px;
    border-top: 1px solid;
    margin: -11px 0;

    @include light-theme {
      border-color: var(--fw-gray-300);
    }
    @include dark-theme {
      border-color: var(--fw-gray-800);
    }
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 12px;
    grid-column: span 4;

    &:last-child {
      border-bottom: 1px solid;
    }

    > .activity-image {

      width: 40px;
      aspect-ratio: 1;
      overflow: hidden;
      border-radius: var(--fw-border-radius);

      > img {
        width: 100%;
        aspect-ratio: 1;
        object-fit: cover;
      }

      > i {
        font-size: 40px;
        line-height: 36px;
      }

      > .play-button {
        position: absolute;
        top: 0;
        left: 0;
        padding: 0 !important;
        width: 100%;
        aspect-ratio: 1;
        margin: 0;
        border: 0 !important;
        opacity: 0;
      }
    }

    &:hover {
      .play-button {
        opacity: 1;
      }
    }

    > .activity-content {

      a {
        text-decoration: none;
        color: var(--color);

        &:hover {
          text-decoration: underline;
        }
      }

      > .track-title {
        font-weight: 700;
        line-height: 1.5em;
        @include dark-theme {
          color: var(--fw-gray-300);
        }
      }

      .artist {
        font-size: 15px;
      }

      .user, time {
        line-height: 1.5em;
        font-size: 0.8125rem;
        color: var(--fw-gray-500);
      }
    }
  }
}

@include light-theme {

  .play-button {
    background: rgba(255, 255, 255, .5);

    &:hover {
      --fw-text-color: var(--fw-gray-800) !important;
    }
  }
}

@include dark-theme {

  .play-button {
    background: rgba(0, 0, 0, .2);

    &:hover {
      background: rgba(0, 0, 0, .8);
      --fw-text-color: var(--fw-gray-200) !important;
    }
  }
}
</style>
