<:Window bind:online />
<div class="timeline" role="feed" aria-label="{{label}}" on:initialized>
  <VirtualList component="{{StatusListItem}}"
               :makeProps
               items="{{statusIds}}"
               on:scrollToBottom="onScrollToBottom()"
               shown="{{initialized}}"
               footerComponent="{{LoadingFooter}}"
               showFooter="{{initialized && runningUpdate}}"
  />
</div>
<style>
  .timeline {
    min-height: 60vh;
  }
</style>
<script>
  import { store } from '../_utils/store'
  import { getTimeline } from '../_utils/mastodon/timelines'
  import StatusListItem from './StatusListItem.html'
  import LoadingFooter from './LoadingFooter.html'
  import VirtualList from './VirtualList.html'
  import { splice, push } from 'svelte-extras'
  import { mergeStatuses } from '../_utils/statuses'
  import { mark, stop } from '../_utils/marks'
  import { timelines } from '../_static/timelines'
  import { toast } from '../_utils/toast'
  import { database } from '../_utils/database/database'

  const FETCH_LIMIT = 20

  export default {
    async oncreate() {
      let statuses = await this.fetchStatusesAndPossiblyFallBack()
      this.addStatuses(statuses)
      requestAnimationFrame(() => {
        requestAnimationFrame((() => {
          this.set({initialized: true})
          this.fire('initialized')
        }))
      })
    },
    data: () => ({
      StatusListItem: StatusListItem,
      LoadingFooter: LoadingFooter,
      statusIds: [],
      runningUpdate: false,
      initialized: false
    }),
    computed: {
      makeProps: ($currentInstance) => (statusId) => database.getStatus($currentInstance, statusId),
      lastStatusId: (statusIds) => statusIds.length && statusIds[statusIds.length - 1],
      label: (timeline, $currentInstance) => {
        if (timelines[timeline]) {
          `${timelines[timeline].label} timeline for ${$currentInstance}`
        } else if (timeline.startsWith('tag/')) {
          let tag = timeline.split('/').slice(-1)[0]
          return `#${tag} timeline for ${$currentInstance}`
        } else if (timeline.startsWith('account/')) {
          let account = timeline.split('/').slice(-1)[0]
          return `Account #${account} on ${$currentInstance}`
        }
      }
    },
    store: () => store,
    components: {
      VirtualList
    },
    methods: {
      splice: splice,
      push: push,
      async onScrollToBottom() {
        if (!this.get('initialized')) {
          return
        }
        if (this.get('runningUpdate')) {
          return
        }
        mark('onScrollToBottom')
        this.set({ runningUpdate: true })
        let newStatuses = await this.fetchStatusesAndPossiblyFallBack()
        this.set({ runningUpdate: false })
        this.addStatuses(newStatuses)
        stop('onScrollToBottom')
      },
      addStatuses(newStatuses) {
        if (process.env.NODE_ENV !== 'production') {
          console.log('addStatuses()')
        }
        let instanceName = this.store.get('instanceName')
        let timeline = this.get('timeline')
        /* no await */ database.insertStatuses(instanceName, timeline, newStatuses)
        let statusIds = this.get('statusIds')
        if (!statusIds) {
          return
        }
        let newStatusIds = newStatuses.map(status => status.id)
        let merged = mergeStatuses(statusIds, newStatusIds)
        this.set({ statusIds: merged })
      },
      async fetchStatusesAndPossiblyFallBack() {
        let online = this.get('online')
        let instanceName = this.store.get('currentInstance')
        let instanceData = this.store.get('currentInstanceData')
        let timeline = this.get('timeline')
        let lastStatusId = this.get('lastStatusId')
        let statuses
        if (!online) {
          statuses = await database.getTimeline(instanceName, timeline, lastStatusId, FETCH_LIMIT)
        } else {
          try {
            statuses = await getTimeline(instanceName, instanceData.access_token, timeline, lastStatusId, FETCH_LIMIT)
            /* no await */ database.insertStatuses(instanceName, timeline, statuses)
          } catch (e) {
            console.error(e)
            toast.say('Internet request failed. Showing offline content.')
            statuses = await database.getTimeline(instanceName, timeline, lastStatusId, FETCH_LIMIT)
          }
        }
        return statuses
      }
    }
  }
</script>