import * as Sentry from '@sentry/react'
import React from 'react'

import { LogErrorType } from 'common/log'

import { ErrorPanel } from './Error'
import PageLoader from './Placeholder'

type DbaaSBoundaryProps = any
interface IDbaaSBoundaryState {
  error?: any
}

const isChunkLoadError = (error?: Error) => {
  if (!error) {
    return false
  }
  if (error.name === 'ChunkLoadError' || /Loading chunk [\d]+ failed/.test(error.message)) {
    return true
  }
  return false
}

export default class DbaaSBoundary extends React.Component<DbaaSBoundaryProps, IDbaaSBoundaryState> {
  constructor(props: DbaaSBoundaryProps) {
    super(props)
    this.state = { error: null }
  }

  public componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    this.setState({ error })
    const chunkError = isChunkLoadError(error)
    Sentry.withScope((scope) => {
      Object.keys(errorInfo).forEach((key) => {
        scope.setExtra(key, errorInfo[key])
      })
      Sentry.captureException(error, {
        level: chunkError ? 'warning' : 'error',
        tags: {
          errorTriage: LogErrorType.UnknownError,
          errorBoundary: 'yes'
        }
      })
    })
    if (chunkError) {
      Sentry.captureMessage('Reload after loading chunk failed', {
        level: 'warning',
        tags: {
          errorTriage: LogErrorType.StaticResourceError
        }
      })
      // send immediately
      Sentry.flush(1000).then(() => {
        window.location.reload()
      })
    }
  }

  public render() {
    if (isChunkLoadError(this.state.error)) {
      return <PageLoader />
    }
    if (this.state.error) {
      // render fallback UI
      return <ErrorPanel />
    } else {
      // when there's not an error, render children untouched
      return this.props.children
    }
  }
}
