<template lang="pug">
.page--list.f-col.between
    article.f-grow

        header.center.t-up
            .title.f-row
                h3 {{ type }} list
                span(v-if="sortBy")
                    h3 sorted {{ sortBy.replace('-', ' ') }}

            h3(v-if="!loaded") loading...
            .content(
                v-else-if="allPagesLoaded && type && allPages[type]"
                v-html="allPages[type].content"
            )

        ul.posts.f-col(v-if="posts && loaded" :class="{ 'is-grid': grid }")
            li(v-for="(post, i) in posts" :key="post.slug").post.shadow
                card(:content="post" :type="type" :wide="isWide")
        
        //- Important: Do NOT remove this! Required for intersection observer
        footer
            p(v-if="loadingFetched") loading more {{ type }}...
            p(v-if="showMeta") {{ `${type} count: ${Object.values(posts).length}` }}
            p(v-if="showMeta") {{ `show sidebar: ${sidebar}` }}

    sidebar(v-if="sidebar" :type="`${type}`" layout="list")
</template>

<script>
import featuredImage from '@/components/featured-image'
import card from '@/components/card'
import sidebar from '@/components/sidebars/sidebar'
import { postTypeGetters, scrollTop, heroUtils } from './mixin-post-types'

import { postTypes, sortTypes, convertTitleCase, typeFromRoute } from '@/utils/helpers'

const TIMEOUT = 1
const INTERSECT_SELECTOR = '.page--list > article footer'

export default {
    components: { sidebar, featuredImage, card },
    props: {
        sidebar: { type: Boolean },
        grid: { type: Boolean },
        sortBy: { type: String },
    },
    mixins: [postTypeGetters, scrollTop, heroUtils],
    data() {
        return {
            showMeta:false,
            page: 0,
            perPage: 21,
            keepFetching: true,
            loadingFetched: false,
            observer: null
        }
    },
    computed: {
        type() {
            // Checks for type and fixes Episodes route edge case
            return typeFromRoute(this.$route)
        },
        pType() {
            if(!typeFromRoute(this.$route)) return
            return this.sortBy ? `${convertTitleCase(typeFromRoute(this.$route).split('/')[0])}s` : `${convertTitleCase(this.type)}s`
        },
        loaded() {
            if (!this.pType) return
            return this[`all${this.pType}Loaded`]
        },
        posts() {
            if (!this.pType) return
            return this[`all${this.pType}`]
        },
        isWide() {
            const wide = ['exhibition', 'event']
            return wide.includes(this.type)
        }
    },
    methods: {
        clearAllPosts() {
            if(!this.type) return console.error(`type: ${this.type}...`)
            const uppercaseType = this.type.toUpperCase() + 'S'
            this.$store.commit(`CLEAR_${uppercaseType}`)
            this.$store.commit(`${uppercaseType}_LOADED`)
        },
        async loadMorePosts() {
            if(!this.type) return console.warn(`this.type: ${type} not found...`)
            if(!this.keepFetching) return console.warn('nothing left to fetch...')

            this.loadingFetched = true
            // console.warn(`loading page ${this.page + 1} of ${type} posts: ${this.page * this.perPage + 1} to ${(this.page + 1) * this.perPage}`)

            this.page++
            await this.getPosts()
        },
        _getSortBy() {
            return this.sortBy
                ? this.sortBy
                : this.$route.path
                      .split('/')
                      .filter(p => p)
                      .pop()
        },
        _getDispatchParams(perPage) {
            return {
                sortType: this._getSortBy(),
                params: {
                    limit: perPage ? perPage : this.perPage,
                    page: this.page
                }
            }
        },
        async getPosts() {
            let dispatchAction = `getMore${this.pType}`
            let params = this._getDispatchParams()
            
            // For episodes, or material sort we grab EVERYTHING
            const getAllClause = this.type == 'episode' || this.type == 'artist' && this._getSortBy() == sortTypes.material
            if(getAllClause) {
                dispatchAction = `getAll${this.pType}`
                params = this._getDispatchParams(-1)
                
                // Clear sortType if this is an episodes list
                params.sortType = this.type == 'episode' ? null : params.sortType
            }

            let res = null
            // We always grab all pages on hero init so no need to do it here
            if(this.pType && this.keepFetching && this.type != 'page') {
                res = await this.$store.dispatch(dispatchAction, params)
            }

            // Stop trying to load more posts
            if(res && !res.length || getAllClause) {
                console.warn(`empty response for ${this.type}:`, res)
                this.keepFetching = false
            }
            this.loadingFetched = false
        },
        async getPageForType(type) {
            await this._getAll('page', this.$store)
            if(!this.allPages) return console.warn('no pages in state', this)
            const page = this.allPages.filter(page => page.slug == `${type}s`)[0]
            if(!page) return console.warn(`no page for ${type} found`)
            return page
        },
        // _setHeroInfo(post) {} from mixin
        // _clearHero(store) {} from mixin
        async checkAndSetHero(type) {
            this._clearHero(this.$store)
            const page = await this.getPageForType(type)
            // We always set a hero no matter what
            // Because the hero component will deal
            // with how to render based on hero.url
            this.$store.commit('SET_HERO', this._setHeroInfo(page))
        },
        setIntersectionLoader() {
            if(!this.type) return console.error('cannot setup intersection handler for undefined type')
            
            // KeepFetching is UNSET for certain post types and sort types in `loadMorePosts()`
            if(!this.keepFetching) return console.warn('cannot setup intersection handler keepFetching is set false')
            
            console.warn('Setting interesection loader...')
            
            // Always unset and reset the intersection loader
            this.unsetIntersectionLoader()

            const onIntersect = (entries, observer) => {
                entries.forEach(entry => {
                    if (!entry.isIntersecting || this.loadingFetched) return
                    setTimeout(() => this.loadMorePosts(), TIMEOUT)
                })
            }
            this.observer = new IntersectionObserver(onIntersect, { threshold: 0.80 })
            this.observer.observe(document.querySelector(INTERSECT_SELECTOR))
            console.log('--- observer')
            console.log(this.observer)
        },
        unsetIntersectionLoader() {
            const footerEl = document.querySelector(INTERSECT_SELECTOR)
            try {
                if(!footerEl) throw `cannot unset intersection handler missing el: ${footerEl}`
                if(!this.observer) throw `cannot unset intersection handler missing observer: ${this.observer}`
                this.observer.unobserve(footerEl)
                this.observer.disconnect()
            } catch (error) {
                console.error(error)
            }
        },
        clearAndInitPostList(caller) {
            console.log(`clearAndInitPostList from ${caller}...`)
            console.log('---')

            this.page = 0
            this.keepFetching = true

            this.checkAndSetHero(this.type)

            // Fires when loading from home
            // Clear any preloaded posts (from home, etc.)
            this.clearAllPosts()
            this.loadMorePosts()

            this.setIntersectionLoader()
        }
    },
    watch: {
        // This only fires navigating from
        // a list page, to another list page
        // and the post type has changed
        type(newType, oldType) {
            if(!postTypes.includes(newType)) return console.warn('type not found...')

            this.clearAndInitPostList('type watcher')
        },
        // Only fire if the sort type has changed
        // and the post type is the same
        $route(to, from) {
            const findSortBy = route => {
                return route.sortBy ? route.sortBy : route.fullPath
                    .split('/')
                    .filter(p => p)
                    .pop()
            }
            if (findSortBy(to) != findSortBy(from) && typeFromRoute(to) == typeFromRoute(from)) {
                this.clearAndInitPostList('$route watcher')
            } 
        }
    },
    mounted() {
        // This only fires navigating from a single page, to a list page
        this.clearAndInitPostList('mounted')
    },
    beforeDestroy() {
        this.unsetIntersectionLoader()
    }
}
</script>

<style lang="postcss">
// prettier-ignore
@import '../sss/variables.sss'
@import '../sss/theme.sss'
.page--list article
    > header
        padding: 1em
        > h1
            margin: 0
        > .content
            padding: 0
            width: 100%
    > footer
        padding: $ms-0

    /* posts not grid list */
    .posts
        list-style: none
        grid-gap: $ms--2
        .post
            width: 100%

    /* posts in grid list */
    .posts.is-grid
        width: 100%
        display: grid
        grid-template-columns: repeat(1, 1fr)
        align-items: start
        /* This is important for how the grid lines up to the page */
        justify-content: right 
        .post img
            width: 100%

@media (min-width: $medium)
    .page--list
        &.f-col
            flex-direction: row
        > article
            margin: 0 $ms--2 0 0
            .posts.is-grid
                grid-template-columns: repeat(3, 1fr)
</style>
