/**
 * PostList view
 *
 * Generated by coz on 2016-12-11,
 * from a template provided by apeman-asset-templates.
 *
 * @function ThreadPostsView
 */
'use strict'

import React, { Component, PropTypes as types } from 'react'
import defineDebug from 'debug'
import {
  ApView, ApViewHeader, ApViewBody, ApViewFooter
} from 'apeman-react-basic'
import { PostList } from '../../fragments'
import {
  asConnected,
  asView,
  asLocaled,
  asServed,
  forList,
  forSpin,
  forOne,
  forAuth,
  forEvent,
  forThreaded,
  forStarrable,
  forBannable,
  forLink,
  forReportable,
  forPosted,
  ofThread,
  combine
} from '../../wrappers'

import { StackWays, ViewEvents } from 'ore-fol-enums'

const debug = defineDebug('project:view:post-list')
const { NONE_WAY } = StackWays
const {
  COMMENT_CREATE_EVENT,
  POST_CREATE_EVENT,
  POST_DESTROY_EVENT,
  POST_BAN_EVENT,
  POST_UNBAN_EVENT
} = ViewEvents

/** @lends ThreadPostsView */
class ThreadPostsView extends Component {
  // --------------------
  // Specs
  // --------------------
  static get propTypes () {
    return {}
  }

  static get defaultProps () {
    return {}
  }

  render () {
    const s = this
    const {
      props,
      l
    } = s

    let {
      posts
    } = props
    return (
      <ApView id='thread-posts-view'
              className='view'
              spinning={ props.spinning }
              way={ props.way }
      >
        <ApViewHeader onLeftTap={ s.handlePop }
                      leftText={ null }
                      leftIcon={ props.popIcon }
                      titleText={ null }
                      titleIcon={ null }
                      onRightTap={ null }
                      rightIcon={ null }
                      rightText={ null }
        />

        <ApViewBody>
          {
            posts ? (
                <div>
                  <PostList wrap
                            posts={ posts.entities }
                            starActiveHash={ props.postStarActiveHash }
                            starSpinHash={ props.postStarSpinningHash }
                            bannableHash={ props.postBannableHash }
                            destroyableHash={ s.getPostDestroyableHash(posts.entities) }
                            tipOpenHash={ props.threadTipOpenHash }
                            ellipsesOpenHash={ props.postEllipsesOpenHash }
                            onDetail={ s.handleDetail }
                            onStar={ s.handleStar }
                            onComments={ s.handleComments }
                            onEllipses={ s.handlePostEllipses }
                            onTip={ s.handleThreadTip }
                            onShare={ s.handleShare }
                            alt={ l('alt.NO_POST_FOUND') }
                            hasMore={ posts.more }
                            moreText={ l('buttons.SHOW_MORE') }
                            onMore={ s.handleMore }
                            moreSpinning={ props.moreSpinning }
                            onReport={ s.handleReport }
                            onTag={ s.handleTag }
                            onBan={ s.handleBan }
                            onDestroy={ s.handleDestroy }
                  />
                </div>
              ) : null
          }
        </ApViewBody>
      </ApView>
    )
  }

  // --------------------
  // Lifecycle
  // --------------------

  componentWillMount () {
    debug('willMount')
    const s = this
  }

  componentDidMount () {
    debug('didMount')
    const s = this
    const { props } = s

    let { threadId } = props
    s.loadPosts(threadId)

    // TODO Reload only related posts

    s.listenEvent(POST_CREATE_EVENT, s.reloadPosts)
    s.listenEvent(POST_DESTROY_EVENT, s.reloadPosts)
    s.listenEvent(COMMENT_CREATE_EVENT, s.reloadPosts)
    s.listenEvent(POST_BAN_EVENT, s.reloadPosts)
    s.listenEvent(POST_UNBAN_EVENT, s.reloadPosts)
  }

  componentWillUnmount () {
    debug('willUnmount')
    const s = this
  }

  // --------------------
  // Handlers
  // --------------------

  handleMore () {
    const s = this
    const { props } = s
    let { threadId, posts } = props
    let { next: offset } = posts.counts
    s.loadMorePosts(threadId, { offset })
  }

  handleDetail ({ id: postId }) {
    const s = this
    let { threadId } = s.props
    s.handlePushToModal('PostDetailView', {
      threadId, postId
    }, {
      way: NONE_WAY
    })
  }

  handleStar ({ id: postId }) {
    const s = this
    const { useAll } = s.service('apiService')
    s.ifAuthorized((signed) => {
      const { props } = s
      s.setPostStarSpinning(postId, true)
      let { postStarActiveHash = {} } = props
      useAll([ 'starApi', 'postApi' ])
        .then(([ starApi, postApi ]) =>
          starApi
            .toggleForPost(postId, !postStarActiveHash[ postId ])
            .then(() =>
              s.applyListUpdate({
                posts: () => postApi.one(postId)
              })
            )
        )
        .then(() =>
          s.loadPostStarHash(s.getLoadedPostIds())
        )
        .then(() =>
          s.setPostStarSpinning(postId, false)
        )
    })
  }

  handleComments ({ id: postId }) {
    const s = this
    s.handlePush('PostCommentsView', { postId })
  }

  handleShare ({ id: postId }) {
    const s = this
    s.handlePushToModal('PostShareView', { postId })
  }

  handleTag ({ id: postId, threadId }) {
    const s = this
    s.ifAuthorized(() =>
      s.handlePushToModal('PostTagView', { threadId, postId })
    )
  }

  handleBan ({ id: postId }) {
    const s = this
    s.ifAuthorized(() =>
      s.handlePushToModal('PostBanView', { postId })
    )
  }

  handleDestroy ({ id: postId }) {
    const s = this
    s.ifAuthorized(() =>
      s.handlePushToModal('PostDestroyView', { postId })
    )
  }

  // --------------------
  // Custom
  // --------------------

  loadPosts (threadId) {
    const s = this
    const { use } = s.service('apiService')
    return use('postApi').then((postApi) =>
      s.applySpinWhile(() =>
        s.applyListLoad({
          posts: () => postApi.listForThread(threadId, {})
        }).then(() => {
          let postIds = s.getLoadedPostIds()
          s.loadPostStarHash(postIds)
          let { signed } = s.props
          if (signed) {
            s.loadPostBannableHash(postIds)
          }
        })
      )
    )
  }

  loadMorePosts (threadId, { offset }) {
    const s = this
    const { use } = s.service('apiService')
    return use('postApi').then((postApi) =>
      s.applySpinWhile({
        moreSpinning: () =>
          s.applyListMore({
            posts: () => postApi.listForThread(threadId, { offset })
          })
            .then(() => {
              let postIds = s.getLoadedPostIds()
              s.loadPostStarHash(postIds)
            })
      })
    )
  }

  reloadPosts () {
    const s = this
    let { threadId } = s.props
    s.loadPosts(threadId)
  }

  getLoadedPostIds () {
    const s = this
    const { props } = s
    let { posts } = props
    if (!posts) {
      return []
    }
    return posts.entities.map((entry) => entry.id)
  }

  getPostDestroyableHash (posts) {
    const s = this
    if (!posts) {
      return {}
    }
    let { signed } = s.props
    if (!signed) {
      return {}
    }
    return posts.reduce((hash, post) => Object.assign(hash, {
      [post.id]: Number(post.submitterId) === Number(signed.id)
    }), {})
  }

}

export default combine(
  asServed(),
  forSpin(),
  forList(),
  forAuth(),
  forOne(),
  forLink(),
  ofThread(),
  forStarrable(),
  forThreaded(),
  forBannable(),
  forReportable(),
  forPosted(),
  asLocaled(),
  asView(),
  forEvent(),
  asConnected(() => ({}))
)(ThreadPostsView)

