import store from '../store/index'
import { calculatePublishedDate } from './utils'

/**
 * Filtering and sort based on user preferences
 * @param {any[]} videos
 */
export function updateVideoListAfterProcessing(videos) {
  let videoList = videos

  if (store.getters.getHideLiveStreams) {
    videoList = videoList.filter(item => {
      return (!item.liveNow && !item.isUpcoming)
    })
  }

  if (store.getters.getHideUpcomingPremieres) {
    videoList = videoList.filter(item => {
      if (item.isRSS) {
        // viewCount is our only method of detecting premieres in RSS
        // data without sending an additional request.
        // If we ever get a better flag, use it here instead.
        return item.viewCount !== '0'
      }
      // Observed for premieres in Local API Subscriptions.
      return (item.premiereDate == null ||
        // Invidious API
        // `premiereTimestamp` only available on premiered videos
        // https://docs.invidious.io/api/common_types/#videoobject
        item.premiereTimestamp == null
      )
    })
  }

  if (store.getters.getHideWatchedSubs) {
    const historyCacheById = store.getters.getHistoryCacheById

    videoList = videoList.filter((video) => {
      return !Object.hasOwn(historyCacheById, video.videoId)
    })
  }

  // ordered last to show first eligible video from channel
  // if the first one incidentally failed one of the above checks
  if (store.getters.getOnlyShowLatestFromChannel) {
    const authors = new Set()
    videoList = videoList.filter((video) => {
      if (!video.authorId) {
        return true
      } else if (!authors.has(video.authorId)) {
        authors.add(video.authorId)
        return true
      }

      return false
    })
  }

  videoList.sort((a, b) => {
    return b.publishedDate - a.publishedDate
  })

  return videoList
}

/**
 * @param {string} rssString
 * @param {string} channelId
*/
export async function parseYouTubeRSSFeed(rssString, channelId) {
  // doesn't need to be asynchronous, but doing it allows us to do the relatively slow DOM querying in parallel
  try {
    const xmlDom = new DOMParser().parseFromString(rssString, 'application/xml')
    const channelName = xmlDom.querySelector('author > name').textContent
    const entries = xmlDom.querySelectorAll('entry')

    const promises = []

    for (const entry of entries) {
      promises.push(parseRSSEntry(entry, channelId, channelName))
    }

    return await Promise.all(promises)
  } catch (e) {
    return []
  }
}

/**
 * @param {Element} entry
 * @param {string} channelId
 * @param {string} channelName
 */
async function parseRSSEntry(entry, channelId, channelName) {
  // doesn't need to be asynchronous, but doing it allows us to do the relatively slow DOM querying in parallel
  const published = new Date(entry.querySelector('published').textContent)

  return {
    authorId: channelId,
    author: channelName,
    // querySelector doesn't support xml namespaces so we have to use getElementsByTagName here
    videoId: entry.getElementsByTagName('yt:videoId')[0].textContent,
    title: entry.querySelector('title').textContent,
    publishedDate: published,
    publishedText: published.toLocaleString(),
    viewCount: entry.getElementsByTagName('media:statistics')[0]?.getAttribute('views') || null,
    type: 'video',
    lengthSeconds: '0:00',
    isRSS: true
  }
}

/**
 * @param {{
 *  liveNow: boolean,
 *  isUpcoming: boolean,
 *  premiereDate: Date,
 *  publishedText: string,
 *  publishedDate: number
 * }[]} videos publishedDate is added by this function,
 * but adding it to the type definition stops vscode warning that the property doesn't exist
 */
export function addPublishedDatesLocal(videos) {
  videos.forEach(video => {
    if (video.liveNow) {
      video.publishedDate = new Date().getTime()
    } else if (video.isUpcoming) {
      video.publishedDate = video.premiereDate
    } else {
      video.publishedDate = calculatePublishedDate(video.publishedText)
    }
    return video
  })
}

/**
 * @param {{
 *  liveNow: boolean,
 *  isUpcoming: boolean,
 *  premiereTimestamp: number,
 *  published: number,
 *  publishedDate: number
 * }[]} videos publishedDate is added by this function,
 * but adding it to the type definition stops vscode warning that the property doesn't exist
 */
export function addPublishedDatesInvidious(videos) {
  videos.forEach(video => {
    if (video.liveNow) {
      video.publishedDate = new Date().getTime()
    } else if (video.isUpcoming) {
      video.publishedDate = new Date(video.premiereTimestamp * 1000)
    } else {
      video.publishedDate = new Date(video.published * 1000)
    }
    return video
  })
}
