import * as React from "react"
import styled from "styled-components"
import * as Toast from "../Toast"
import gql from "graphql-tag"
import * as cookie from "js-cookie"
import { withApollo } from "react-apollo"
import { getConfig } from "jamplay-common/remote-config"
import ApolloClient from "apollo-client"

const Container = styled.div`
  position: fixed;
  z-index: 100;
  top: 100px;
  right: 30px;
  & > * {
    margin-bottom: 10px;
    animation: fadeIn 1s;
    @keyframes fadeIn {
      from {opacity: 0;}
      to {opacity: 1;}
    }
  }
`

let connection
const POLLING_DURATION = 20000

function createConnection() {
  const t = cookie.get("polling_timestamp") || "0"
  try {
    const latestTimestamp = t ? parseInt(t, 10) : 0
    console.log(Date.now() - latestTimestamp)
    if (Date.now() - latestTimestamp > POLLING_DURATION) {
      console.log(`[notification] polling channel avaliable, start polling ${Date.now()}`)
    } else {
      console.log(`skip polling... (polling already exists try again in ${POLLING_DURATION})`)
      setTimeout(() => createConnection(), POLLING_DURATION)
      return
    }
  } catch (e) {
    console.error(e)
    cookie.set("polling_timestamp", 0)
  }

  const xhr = new XMLHttpRequest()
  const token = cookie.get("token")
  xhr.open(
    "get",
    (getConfig().publicRuntimeConfig.legacyPollingUrl) + `?duration=${POLLING_DURATION}`
  )
  xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8")
  xhr.setRequestHeader("Authorization", `Bearer ${token}`)
  xhr.onprogress = () => {
    // console.log(`[notification] polling.... `)
    const res = (xhr.responseText.toString().split("?;?")).filter((chunk) => chunk.length > 0)
    try {
      console.log(res[res.length - 1])
      if (!res[res.length - 1]) {
        return
      }
      const result = JSON.parse(res[res.length - 1])
      if (result.isUpdated > 0) {
        cookie.set("isUpdateNoti", Number(cookie.get("isUpdateNoti") || 0) + 1)
      }
    } catch (e) {
      console.error(res[res.length - 1], e)
    }
  }
  xhr.onload = () => {
    console.log("[notification] end polling")
    const res = (xhr.responseText.toString().split("?;?")).filter((chunk) => chunk.length > 0)
    try {
      const end = JSON.parse(res[res.length - 1])
      // last chunk should confirm success
      // to restart polling
      console.log(end)
      if (end.done) {
        setTimeout(
          // delay new polling to maintain server performance
          () => {
            (window as any).notificationPolling = createConnection()
          }, 5000
        )
      } else {
        console.warn("[notification] long polling has been interupt...")
      }
    } catch (e) {
      console.warn("[notification] notification service not avaliable")
    }
  }
  xhr.onerror = () => {
    console.warn("[notification] cannot connect to notification polling endpoint reload to retry....")
  }
  xhr.timeout = 50000
  console.log("[notification] start polling")
  cookie.set("polling_timestamp", Date.now())
  xhr.send()

  return xhr
}

export type TProps = {
  client: ApolloClient<any>
}

let version = 0
const markAsRead: boolean[] = []

class ToastNotificationLegacy extends React.Component<TProps, any> {
  public _cancel = false
  public _timer
  public state: any = {
    notifications: []
  }
  public componentDidMount() {
    if (!connection) {
      createConnection()
      connection = 1
    }
    const client = this.props.client
    if (typeof window !== "undefined") {
      this._timer = setInterval(async () => {
        const isUpdateNoti = cookie.get("isUpdateNoti")
        if (isUpdateNoti && version < Number(isUpdateNoti)) {
          version = Number(isUpdateNoti)
          const result = await client.query<any>({
            query: gql`
              query {
                user {
                  _id
                  notifications {
                    text
                    _id
                    textAttr
                    isRead
                  }
                }
              }
            `,
            fetchPolicy: "network-only",
            context: { service: "nap" },
          })
          const notifications = result && result.data && result.data && result.data.user && result.data.user.notifications
            ? result.data.user.notifications : []
          if (notifications.length > 0) {
            // yield put({type: 'app/close-dialog', from: 'notification.sagas'}) --> remove it because it's remove payment-error toast
            const addNoti: any[] = []
            for (const noti of notifications) {
              const isAlreadyShow = markAsRead[noti._id]
              if (!noti.isRead && !isAlreadyShow) {
                markAsRead[noti._id] = true
                addNoti.push(noti)
              }
            }
            if (addNoti.length) {
              this.setState((state) => ({
                notifications: state.notifications.concat(addNoti)
              }))
            }
          }
        }
      }, 1000)
    }
  }
  public componentWillUnmount() {
    clearInterval(this._timer)
  }

  public handleOnClose = (_id) => {
    this.setState(
      (state) =>
        ({ notifications: state.notifications.filter((n) => n._id !== _id)})
    )
  }

  public render() {
    if (typeof window === "undefined") {
      return <Container />
    }
    return (
      <Container>
        {
          this.state.notifications.map((notification) => (
            <Toast.Success
              key={notification._id}
              message={notification.text}
              params={notification.textAttr}
              onClose={this.handleOnClose.bind(this, notification._id)}
            />
          ))
        }
      </Container>
    )
  }
}

export default withApollo<any, any>(ToastNotificationLegacy)
