/**
 * SET 58 — the shell's first law: NOTHING blanks silently.
 *
 * Hard React error boundary + window-level error/rejection hooks. Any throw
 * anywhere renders a crash card carrying the actual error text and a one-click
 * diagnostics copy, instead of a blank page.
 */
import { Component, type ReactNode } from 'react';
import { getSnapshot, noteDiag } from './store';

let hooksInstalled = false;

export function installGlobalErrorHooks(): void {
  if (hooksInstalled) return;
  hooksInstalled = true;
  window.addEventListener('error', ev => {
    noteDiag('window.onerror', false, `${ev.message} @ ${ev.filename}:${ev.lineno}`);
  });
  window.addEventListener('unhandledrejection', ev => {
    const r = (ev as PromiseRejectionEvent).reason;
    noteDiag('unhandledrejection', false, r instanceof Error ? r.message : String(r));
  });
}

function diagnosticsDump(error: unknown, stack?: string | null): string {
  const s = getSnapshot();
  return JSON.stringify({
    when: new Date().toISOString(),
    error: error instanceof Error ? `${error.name}: ${error.message}` : String(error),
    stack: stack ?? (error instanceof Error ? error.stack : null),
    ext: s.ext,
    liveId: s.liveId,
    viewingId: s.viewingId,
    lastError: s.lastError,
    diags: s.diags.slice(-25),
  }, null, 2);
}

export function CrashCard({ error, stack }: { error: unknown; stack?: string | null }) {
  const dump = diagnosticsDump(error, stack);
  return (
    <div className="sh-crash" data-rha-shell="crash">
      <b>The UI hit an error — and this time it tells you what it was.</b>
      <pre className="sh-crash-text">
        {error instanceof Error ? `${error.name}: ${error.message}` : String(error)}
      </pre>
      <div className="sh-crash-actions">
        <button
          type="button"
          className="btn"
          onClick={() => { void navigator.clipboard?.writeText(dump); }}
        >
          Copy diagnostics
        </button>
        <button type="button" className="btn" onClick={() => window.location.reload()}>
          Reload
        </button>
      </div>
      <details style={{ marginTop: 8 }}>
        <summary>Full diagnostics</summary>
        <pre className="sh-crash-text">{dump}</pre>
      </details>
    </div>
  );
}

export class ErrorShield extends Component<
  { children: ReactNode },
  { error: unknown | null; stack: string | null }
> {
  state = { error: null as unknown | null, stack: null as string | null };

  static getDerivedStateFromError(error: unknown) {
    return { error };
  }

  componentDidCatch(error: unknown, info: { componentStack?: string | null }) {
    this.setState({ stack: info?.componentStack ?? null });
    noteDiag('react-boundary', false, error instanceof Error ? error.message : String(error));
  }

  render() {
    if (this.state.error != null) {
      return <CrashCard error={this.state.error} stack={this.state.stack} />;
    }
    return this.props.children;
  }
}
