import React from 'react';
import { Alert } from '@theorchard/suite-components';

interface LazyRouteErrorBoundaryProps {
    children: React.ReactNode;
}

interface LazyRouteErrorBoundaryState {
    hasChunkError: boolean;
}

const isChunkLoadError = (error: Error): boolean =>
    error.name === 'ChunkLoadError' ||
    /Loading chunk \S+ failed/i.test(error.message);

export class LazyRouteErrorBoundary extends React.Component<
    LazyRouteErrorBoundaryProps,
    LazyRouteErrorBoundaryState
> {
    state: LazyRouteErrorBoundaryState = { hasChunkError: false };

    static getDerivedStateFromError(
        error: Error
    ): LazyRouteErrorBoundaryState | null {
        // Only catch chunk-load errors. Returning null for other errors does
        // NOT propagate them — React still considers the boundary "having
        // caught" the error. We must re-throw in componentDidCatch below.
        return isChunkLoadError(error) ? { hasChunkError: true } : null;
    }

    componentDidCatch(error: Error): void {
        // React's documented mechanism for letting an error propagate to a
        // higher boundary: re-throw from componentDidCatch. Without this,
        // non-chunk errors get silently swallowed (state isn't updated, no
        // fallback renders, the error doesn't reach Sentry/Datadog). Will
        // fire twice in StrictMode dev mode; that's acceptable noise.
        if (!isChunkLoadError(error)) {
            throw error;
        }
    }

    handleReload = (): void => {
        window.location.reload();
    };

    render() {
        if (this.state.hasChunkError) {
            // role="alert" wrapper is required for screen-reader announcement.
            // Verified by reading node_modules/@theorchard/suite-components/src/
            // components/alert/alert.tsx:167-183 — Alert renders only visual
            // styling; it sets no ARIA role/live attributes on its root.
            // Alert.button.onClick receives a dismissAlert callback we ignore
            // (signature: (dismiss: () => void) => void). Passing a 0-arg
            // function satisfies TS.
            return (
                <div role="alert">
                    <Alert
                        variant="warn"
                        title="A new version of Abacus is available"
                        text="Please save any unsaved work, then reload to continue."
                        button={{
                            text: 'Reload page',
                            onClick: this.handleReload,
                        }}
                    />
                </div>
            );
        }
        return this.props.children;
    }
}
