import React, { useState, useEffect } from 'react'
import { RefreshControl, RefreshControlProps } from 'react-native'

import { useGet } from './Network'
import { useNetworkStatus } from '../network-status'
import { User } from '../user'
import { ServiceError } from '../errors'

export type NetworkRequest<T> = {
  error: NetworkError | null
  showToast: boolean
  refreshControl: React.ReactElement<RefreshControlProps>
  data?: T
  retry: () => void
  refreshing: boolean
}
export type NetworkError =
  // Exception on app side
  | { type: 'app' }
  // Backend reported an issue back
  | { type: 'service'; eventId: string; status: number }
  // Network connection lost
  | { type: 'offline' }

export function useNetwork<T>(
  path: string,
  user: User,
  onRetry?: () => void
): NetworkRequest<T> {
  const online = useNetworkStatus()
  const [initialLoad, setInitialLoad] = useState(true)
  const [showToast, setShowToast] = useState(false)
  const [refreshing, setRefreshing] = useState(false)

  const response = useGet<T>(path, user)

  const data = response.data
  // Check for undefined as 0 or null could be valid data
  // "data: data for the given key resolved by fetcher (or undefined if not loaded)"
  // https://www.npmjs.com/package/swr
  const loading = data === undefined
  const error: NetworkError | null =
    !online && loading
      ? { type: 'offline' }
      : response.error && !refreshing
      ? response.error instanceof ServiceError
        ? {
            type: 'service',
            status: response.error.status,
            eventId: response.error.eventId,
          }
        : {
            type: 'app',
          }
      : null

  const retry = () => {
    onRetry != null && onRetry()
    if (online) {
      setRefreshing(true)
      setShowToast(false)
      response.revalidate().finally(() => setRefreshing(false))
    } else {
      setRefreshing(false)
      setShowToast(true)
    }
  }

  useEffect(() => {
    if (!initialLoad && loading && online) {
      retry()
    }
  }, [online])

  useEffect(() => {
    setInitialLoad(false)
  }, [])

  const refreshControl = (
    <RefreshControl refreshing={refreshing} onRefresh={retry} />
  )

  return {
    error,
    showToast,
    data,
    refreshControl,
    retry,
    refreshing,
  }
}
