import { Component, type ErrorInfo, type ReactNode } from 'react'
import Alert from '@mui/material/Alert'
import AlertTitle from '@mui/material/AlertTitle'
import Box from '@mui/material/Box'
import Button from '@mui/material/Button'

type Props = {
  children: ReactNode
  fallback?: ReactNode
  onError?: (error: Error, errorInfo: ErrorInfo) => void
}

type State = {
  error: Error | null
}

export class ErrorBoundary extends Component<Props, State> {
  constructor(props: Props) {
    super(props)
    this.state = { error: null }
  }

  static getDerivedStateFromError(error: Error): State {
    return { error }
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
    this.props.onError?.(error, errorInfo)
  }

  private handleReset = (): void => {
    this.setState({ error: null })
  }

  render(): ReactNode {
    if (this.state.error) {
      if (this.props.fallback) return this.props.fallback

      return (
        <Box sx={{ p: 4, display: 'flex', justifyContent: 'center' }}>
          <Box sx={{ maxWidth: 480 }}>
            <Alert severity="error">
              <AlertTitle>Что-то пошло не так</AlertTitle>
              {this.state.error.message || 'Произошла непредвиденная ошибка.'}
            </Alert>
            <Button onClick={this.handleReset} variant="outlined" sx={{ mt: 2 }}>
              Попробовать снова
            </Button>
          </Box>
        </Box>
      )
    }

    return this.props.children
  }
}
