import * as React from "react"
import { graphql, withApollo } from "react-apollo"
import gql from "graphql-tag"
import Stream from "../../Stream"

const q = gql`
  query($after: MongoID) {
    notificationBadge
    notifications(after: $after) {
      endCursor
      hasNextPage
      nodes {
        _id
        type
        payload
        message {
          text
          textAttr
        }
      }
    }
  }
`

const badgeQuery = gql`
  query {
    notificationBadge
  }
`

const withData = graphql<any, any, any, any>(q, {
  props: ({ data }) => ({
    notificationBadge: data ? data.notificationBadge : null,
    notifications: data && data.notifications ? data.notifications.nodes : null,
    hasNextPage:
      data && data.notifications ? data.notifications.hasNextPage : null,
    fetchMore: () => data &&
      data.fetchMore({
        variables: {
          after: data.notifications.endCursor
        },
        updateQuery: (previousResult, { fetchMoreResult }) => {
          if (!fetchMoreResult) {
            return {}
          }
          const newNotifications = fetchMoreResult.notifications
          return {
            ...previousResult,
            notificationBadge: fetchMoreResult.notificationBadge,
            notifications: {
              ...previousResult.notifications,
              endCursor: newNotifications.endCursor,
              hasNextPage: newNotifications.hasNextPage,
              nodes: [].concat(
                previousResult.notifications.nodes,
                newNotifications.nodes
              )
            }
          }
        }
      })
  }),
  options: (props) => ({
    context: {
      service: "notification"
    },
    variables: {}
  })
})

class Component extends React.Component<any, any> {
  public onAction = (action) => {
    try {
      console.log("got action", action)
      if (action.type === "notification/upsert") {
        const data = this.props.client.readQuery({
          query: q,
          variables: {}
        })
        const addedNotification = Object.assign(
          {
            __typename: "Notification"
          },
          action.payload,
          {
            message: Object.assign(
              {
                __typename: "NotificationMessage"
              },
              action.payload && action.payload.message
                ? action.payload.message
                : null
            )
          }
        )
        if (data.notificationBadge >= 0) {
          data.notificationBadge++
        }
        if (data.notifications && data.notifications.nodes) {
          data.notifications.nodes = ([] as any).concat(
            [addedNotification],
            data.notifications.nodes
          )
        }
        this.props.client.writeQuery({
          query: q,
          variables: {},
          data
        })
      } else if (action.type === "notification/clear-badge-count") {
        const data = this.props.client.readQuery({
          query: badgeQuery
        })
        if (data.notificationBadge) {
          data.notificationBadge = 0
        }
        this.props.client.writeQuery({
          query: badgeQuery,
          data
        })
      }
    } catch (error) {
      console.error("apply action error", error)
    }
  }

  public render() {
    return (
      <div>
        <Stream onAction={this.onAction} url={this.props.streamUrl} />
        <div>
          <span>badge:</span>
          <span>{this.props.notificationBadge + ""}</span>
        </div>
        <div>notifications</div>
        {!this.props.notifications
          ? "null"
          : this.props.notifications.map((noti) => (
              <div key={noti._id}>{JSON.stringify(noti)}</div>
            ))}
        {this.props.hasNextPage ? (
          <button onClick={this.props.fetchMore}>load more</button>
        ) : null}
        <br />
        <br />
        <br />
      </div>
    )
  }
}

export default withData(withApollo(Component))
