import * as O from 'fp-ts/Option'
import { useMemo } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import { share, take, timer } from 'rxjs'
import { downloadsState } from '../atoms/downloads'
import { serverAddressAndPortState } from '../atoms/settings'
import { connectedState } from '../atoms/status'
import { useSubscription } from '../hooks/observable'
import { useToast } from '../hooks/toast'
import { useI18n } from '../hooks/useI18n'
import { useRPC } from '../hooks/useRPC'
import { datetimeCompareFunc, isRPCResponse } from '../utils'

interface Props extends React.HTMLAttributes<HTMLBaseElement> { }

const SocketSubscriber: React.FC<Props> = ({ children }) => {
  const [, setIsConnected] = useRecoilState(connectedState)
  const [, setDownloads] = useRecoilState(downloadsState)

  const serverAddressAndPort = useRecoilValue(serverAddressAndPortState)

  const { i18n } = useI18n()
  const { client } = useRPC()
  const { pushMessage } = useToast()

  const sharedSocket$ = useMemo(() => client.socket$.pipe(share()), [])
  const socketOnce$ = useMemo(() => sharedSocket$.pipe(take(1)), [])

  useSubscription(socketOnce$, () => {
    setIsConnected(true)
    pushMessage(
      `${i18n.t('toastConnected')} (${serverAddressAndPort})`,
      "success"
    )
  })

  useSubscription(
    sharedSocket$,
    event => {
      if (!isRPCResponse(event)) { return }
      if (!Array.isArray(event.result)) { return }

      if (event.result) {
        return setDownloads(
          O.of(event.result
            .filter(f => !!f.info.url).sort((a, b) => datetimeCompareFunc(
              b.info.created_at,
              a.info.created_at,
            ))
          )
        )
      }

      setDownloads(O.none)
    },
    err => {
      console.error(err)
      pushMessage(
        `${i18n.t('rpcConnErr')} (${serverAddressAndPort})`,
        "error"
      )
    }
  )

  useSubscription(timer(0, 1000), () => client.running())

  return (
    <>{children}</>
  )
}

export default SocketSubscriber