"use client";

import { Component, type ReactNode } from "react";
import { TriangleAlert } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useT } from "@/i18n";

interface WidgetErrorBoundaryProps {
  children: ReactNode;
  /** Used as a key to hard-remount the boundary when the widget changes. */
  identifier: string;
}

interface WidgetErrorBoundaryState {
  hasError: boolean;
}

/**
 * Catch a widget body crashing at render time so one broken tile never takes
 * down the whole dashboard grid. The retry button resets the boundary and asks
 * the widget to render again — if the bug persists it shows the same fallback.
 */
export class WidgetErrorBoundary extends Component<WidgetErrorBoundaryProps, WidgetErrorBoundaryState> {
  override state: WidgetErrorBoundaryState = { hasError: false };

  static getDerivedStateFromError(): WidgetErrorBoundaryState {
    return { hasError: true };
  }

  componentDidCatch(error: unknown) {
    console.error(`Widget "${this.props.identifier}" crashed:`, error);
  }

  private handleRetry = () => this.setState({ hasError: false });

  override render() {
    if (this.state.hasError) {
      return <WidgetErrorFallback identifier={this.props.identifier} onRetry={this.handleRetry} />;
    }
    return this.props.children;
  }
}

function WidgetErrorFallback({ identifier, onRetry }: { identifier: string; onRetry: () => void }) {
  const t = useT();
  return (
    <div className="flex flex-col items-center gap-3 rounded-lg border border-dashed border-destructive/40 bg-destructive-soft/40 px-4 py-6 text-center">
      <TriangleAlert className="h-5 w-5 text-destructive" aria-hidden />
      <p className="text-sm text-muted-foreground">{t("widgets.widgetError")}</p>
      <p className="text-xs text-muted-foreground/70">{identifier}</p>
      <Button variant="outline" size="sm" onClick={onRetry}>
        {t("common.retry")}
      </Button>
    </div>
  );
}