import type { FC, ComponentType } from 'react';
import React, { useState } from 'react';
import type { ViewStyle } from 'react-native';
import { View } from 'react-native';
import * as sentryService from '../services/sentry.service';
import ErrorBoundary from '../components/Errors/ErrorBoundary';
import useSession from '../hooks/auth/useSession';
import ErrorState from '../components/Errors/ErrorState';
import accessibilityParams from '../accessibility';
import type { POTComponentProps } from '../components/POTComponent/types.ts';
import type { ThemeProps } from '../branding/hoc/types.ts';

interface BaseProps {
    testId?: string;
    customContainerStyles?: ViewStyle;
    accessibilityParam?: any;
}

const withComponentErrorBoundary = <ComponentProps extends object>(
    Component: ComponentType<
        ComponentProps & BaseProps & POTComponentProps & ThemeProps
    >,
    Header: ComponentType<ComponentProps>
): FC<ComponentProps & BaseProps> => {
    const componentName =
        (Component as any).displayName || Component.name || 'Component';

    const WithComponentErrorBoundary: FC<ComponentProps & BaseProps> = ({
        testId,
        customContainerStyles,
        accessibilityParam,
        ...props
    }) => {
        const [error, setError] = useState<any>();
        const [{ currentProfile }] = useSession();

        const handleError = (err: any): void => {
            const profileId = currentProfile?.profileId;
            const profileType = currentProfile?.profileType;
            setError(err);
            sentryService.logException(
                `An error occurred in ${componentName} for profileId ${profileId}, profileType ${profileType}. The error details are: ${
                    err?.message || err
                }`
            );
        };

        if (error) {
            return (
                <View
                    testID={testId}
                    style={customContainerStyles}
                    {...accessibilityParams(accessibilityParam)}
                >
                    <Header {...(props as ComponentProps)} />
                    <ErrorState />
                </View>
            );
        }

        return (
            <ErrorBoundary onError={handleError}>
                <Component
                    {...({
                        ...(props as ComponentProps),
                        testId,
                        customContainerStyles,
                        accessibilityParam
                    } as ComponentProps &
                        BaseProps &
                        POTComponentProps &
                        ThemeProps)}
                />
            </ErrorBoundary>
        );
    };

    return WithComponentErrorBoundary;
};

export default withComponentErrorBoundary;
