'use client';

import { Box, Button, Typography, Paper } from '@mui/material';
import { BrokenImage, CloudOff, BugReport, DataObject } from '@mui/icons-material';
import { ReactNode } from 'react';

interface FallbackProps {
  error?: Error;
  resetError?: () => void;
}

/**
 * Generic minimal error fallback
 */
export function MinimalErrorFallback({ error, resetError }: FallbackProps) {
  return (
    <Box
      sx={{
        p: 2,
        textAlign: 'center',
        bgcolor: 'error.light',
        borderRadius: 2,
        border: '1px solid',
        borderColor: 'error.main',
      }}
    >
      <Typography variant="body2" color="error.dark" gutterBottom>
        Something went wrong
      </Typography>
      {resetError && (
        <Button size="small" onClick={resetError} variant="outlined" color="error">
          Retry
        </Button>
      )}
    </Box>
  );
}

/**
 * Fallback for image loading errors
 */
export function ImageErrorFallback() {
  return (
    <Box
      sx={{
        width: '100%',
        height: '100%',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        bgcolor: 'grey.100',
        borderRadius: 1,
      }}
    >
      <BrokenImage sx={{ fontSize: 48, color: 'grey.400' }} />
    </Box>
  );
}

/**
 * Fallback for API/data fetching errors
 */
export function DataErrorFallback({ error, resetError }: FallbackProps) {
  return (
    <Paper
      sx={{
        p: 3,
        textAlign: 'center',
        bgcolor: 'background.paper',
        border: '1px dashed',
        borderColor: 'divider',
      }}
    >
      <CloudOff sx={{ fontSize: 48, color: 'text.secondary', mb: 2 }} />
      <Typography variant="h6" gutterBottom>
        Failed to Load Data
      </Typography>
      <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
        {error?.message || 'Unable to fetch the requested data. Please try again.'}
      </Typography>
      {resetError && (
        <Button variant="contained" onClick={resetError}>
          Retry
        </Button>
      )}
    </Paper>
  );
}

/**
 * Fallback for rendering errors in components
 */
export function ComponentErrorFallback({ error, resetError }: FallbackProps) {
  return (
    <Box
      sx={{
        p: 3,
        border: '2px dashed',
        borderColor: 'warning.main',
        borderRadius: 2,
        bgcolor: 'warning.light',
      }}
    >
      <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 1 }}>
        <BugReport sx={{ color: 'warning.dark' }} />
        <Typography variant="subtitle1" fontWeight="600" color="warning.dark">
          Component Error
        </Typography>
      </Box>
      <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
        This component failed to render. The rest of the page should still work.
      </Typography>
      {process.env.NODE_ENV === 'development' && error && (
        <Typography
          variant="caption"
          component="pre"
          sx={{
            p: 1,
            bgcolor: 'background.paper',
            borderRadius: 1,
            overflow: 'auto',
            fontSize: '0.7rem',
          }}
        >
          {error.message}
        </Typography>
      )}
      {resetError && (
        <Button size="small" variant="outlined" onClick={resetError} sx={{ mt: 1 }}>
          Reload Component
        </Button>
      )}
    </Box>
  );
}

/**
 * Fallback for form errors
 */
export function FormErrorFallback({ error, resetError }: FallbackProps) {
  return (
    <Paper
      elevation={0}
      sx={{
        p: 2,
        bgcolor: 'error.light',
        border: '1px solid',
        borderColor: 'error.main',
        borderRadius: 2,
      }}
    >
      <Typography variant="subtitle2" color="error.dark" gutterBottom>
        Form Submission Error
      </Typography>
      <Typography variant="body2" color="error.dark" sx={{ mb: 2 }}>
        {error?.message || 'Unable to process your form. Please try again.'}
      </Typography>
      {resetError && (
        <Button size="small" variant="contained" color="error" onClick={resetError}>
          Try Again
        </Button>
      )}
    </Paper>
  );
}

/**
 * Fallback for data visualization/chart errors
 */
export function ChartErrorFallback({ resetError }: FallbackProps) {
  return (
    <Box
      sx={{
        height: 300,
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
        justifyContent: 'center',
        bgcolor: 'grey.50',
        borderRadius: 2,
        border: '1px dashed',
        borderColor: 'divider',
      }}
    >
      <DataObject sx={{ fontSize: 48, color: 'text.disabled', mb: 2 }} />
      <Typography variant="body2" color="text.secondary" gutterBottom>
        Unable to display chart
      </Typography>
      {resetError && (
        <Button size="small" onClick={resetError} sx={{ mt: 1 }}>
          Reload
        </Button>
      )}
    </Box>
  );
}

/**
 * Wrapper component to easily apply error boundary with custom fallback
 */
interface ErrorBoundaryWrapperProps {
  children: ReactNode;
  fallbackType?: 'minimal' | 'component' | 'data' | 'form' | 'chart';
  customFallback?: ReactNode;
}

export function withErrorBoundary<P extends object>(
  Component: React.ComponentType<P>,
  fallbackType: ErrorBoundaryWrapperProps['fallbackType'] = 'component'
) {
  return function WithErrorBoundaryWrapper(props: P) {
    const { ErrorBoundary } = require('./ErrorBoundary');

    const getFallback = (error: Error, resetError: () => void) => {
      switch (fallbackType) {
        case 'minimal':
          return <MinimalErrorFallback error={error} resetError={resetError} />;
        case 'data':
          return <DataErrorFallback error={error} resetError={resetError} />;
        case 'form':
          return <FormErrorFallback error={error} resetError={resetError} />;
        case 'chart':
          return <ChartErrorFallback resetError={resetError} />;
        case 'component':
        default:
          return <ComponentErrorFallback error={error} resetError={resetError} />;
      }
    };

    return (
      <ErrorBoundary isolate fallback={(error: Error, reset: () => void) => getFallback(error, reset)}>
        <Component {...props} />
      </ErrorBoundary>
    );
  };
}
