"use client";

import React from "react";
import {Button} from "@/components/ui/button";
import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogFooter,
    DialogHeader,
    DialogTitle,
} from "@/components/ui/dialog";

interface ErrorBoundaryState {
    hasError: boolean;
    error: Error | null;
    errorInfo: React.ErrorInfo | null;
}

interface ErrorBoundaryProps {
    children: React.ReactNode;
    fallback?: React.ComponentType<{ error: Error; reset: () => void }>;
}

export class ErrorBoundary extends React.Component<
    ErrorBoundaryProps,
    ErrorBoundaryState
> {
    constructor(props: ErrorBoundaryProps) {
        super(props);
        this.state = {
            hasError: false,
            error: null,
            errorInfo: null,
        };
    }

    static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {
        return {
            hasError: true,
            error,
        };
    }

    componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
        console.error("ErrorBoundary caught an error:", error, errorInfo);

        this.setState({
            error,
            errorInfo,
        });
    }

    handleReset = () => {
        this.setState({
            hasError: false,
            error: null,
            errorInfo: null,
        });
    };

    render() {
        if (this.state.hasError) {
            if (this.props.fallback) {
                const FallbackComponent = this.props.fallback;
                return (
                    <FallbackComponent
                        error={this.state.error!}
                        reset={this.handleReset}
                    />
                );
            }

            return (
                <ErrorDialog
                    error={this.state.error}
                    onReset={this.handleReset}
                    open={true}
                />
            );
        }

        return this.props.children;
    }
}

interface ErrorDialogProps {
    error: Error | null;
    onReset: () => void;
    open: boolean;
}

function ErrorDialog({error, onReset, open}: ErrorDialogProps) {
    return (
        <Dialog open={open} onOpenChange={(isOpen) => {
            if (!isOpen) {
                onReset();
            }
        }}>
            <DialogContent className="sm:max-w-md">
                <DialogHeader>
                    <DialogTitle>Uncaught Error!</DialogTitle>
                    <DialogDescription>
                        Es ist ein unerwarteter Fehler aufgetreten.
                    </DialogDescription>
                </DialogHeader>

                {error && (
                    <div className="mt-4 p-4 bg-red-50 dark:bg-red-900/20 rounded-md">
                        <p className="text-sm text-red-800 dark:text-red-200 font-mono">
                            {error.message}
                        </p>
                    </div>
                )}

                <DialogFooter className="flex gap-2">
                    <Button variant="outline" onClick={() => window.location.reload()}>
                        Seite neu laden
                    </Button>
                    <Button onClick={onReset}>
                        Erneut versuchen
                    </Button>
                </DialogFooter>
            </DialogContent>
        </Dialog>
    );
}

// Hook for handling async errors
export function useErrorHandler() {
    const [errorState, setErrorState] = React.useState();

    console.log('Current state:', errorState);

    return React.useCallback((error: unknown) => {
        console.error("Async error caught:", error);

        // Trigger a re-render that will throw the error and be caught by the error boundary 
        setErrorState(() => {
            throw error instanceof Error ? error : new Error(String(error));
        });
    }, []);
}
