(() => {
  const { useEffect, useRef } = React;
  const { Icon } = window.HiraIcons;

function useTheme(dark) {
  return React.useMemo(() => dark
    ? {
        bg: "bg-[#0a0c16]", text: "text-stone-200", sub: "text-stone-500", faint: "text-stone-600",
        panel: "bg-white/[0.04] border-white/10", ring: "ring-white/[0.08]", railBg: "border-white/5",
        overlay: "bg-black/85", chipInactive: "border-white/10 text-stone-400",
        modalBg: "bg-[#12141f] border-white/10", inputBg: "bg-white/[0.04] border-white/10 text-stone-100 placeholder-stone-500",
        hoverSoft: "hover:bg-white/[0.06]", dropdownBg: "bg-[#1a1d2e] border-white/10",
      }
    : {
        bg: "bg-[#faf6ee]", text: "text-stone-800", sub: "text-stone-500", faint: "text-stone-400",
        panel: "bg-white border-stone-200", ring: "ring-stone-900/[0.08]", railBg: "border-stone-200",
        overlay: "bg-black/80", chipInactive: "border-stone-300 text-stone-500",
        modalBg: "bg-white border-stone-200", inputBg: "bg-stone-100 border-stone-200 text-stone-800 placeholder-stone-400",
        hoverSoft: "hover:bg-stone-100", dropdownBg: "bg-white border-stone-200",
      }, [dark]);
}

function EmptyState({ T, title = "Belum ada data", body = "Coba muat ulang atau ubah filter.", action }) {
  return (
    <div className="flex flex-col items-center justify-center py-20 text-center">
      <div className={`w-14 h-14 rounded-2xl border ${T.chipInactive} flex items-center justify-center mb-4 text-amber-400`}><Icon.Image /></div>
      <p className="font-display text-lg mb-1">{title}</p>
      <p className={`text-sm ${T.sub} max-w-xs`}>{body}</p>
      {action && <div className="mt-5">{action}</div>}
    </div>
  );
}

function SkeletonGrid({ T, count = 8 }) {
  return (
    <div className="columns-2 sm:columns-3 lg:columns-4 xl:columns-5 gap-4">
      {Array.from({ length: count }).map((_, i) => (
        <div key={i} className="break-inside-avoid mb-5 card-enter">
          <div className={`rounded-2xl overflow-hidden skeleton-shimmer ${T.panel}`} style={{ minHeight: 160 + (i % 3) * 60 }} />
          <div className="flex items-start justify-between gap-1.5 px-0.5 pt-2">
            <div className={`h-3 w-3/4 rounded skeleton-shimmer ${T.panel}`} />
            <div className={`h-3 w-3 rounded-full skeleton-shimmer ${T.panel} shrink-0`} />
          </div>
        </div>
      ))}
    </div>
  );
}

// ── Toast Notification ───────────────────────────────────────────────────────
function Toast({ message, type, visible, onHide }) {
  const onHideRef = useRef(onHide);
  useEffect(() => { onHideRef.current = onHide; }, [onHide]);
  useEffect(() => {
    if (!visible) return undefined;
    const t = setTimeout(() => onHideRef.current?.(), 2600);
    return () => clearTimeout(t);
  }, [visible, message, type]);

  if (!visible) return null;
  const color = type === "error" ? "bg-rose-500" : type === "success" ? "bg-emerald-500" : "bg-amber-400 text-[#0a0c16]";
  return (
    <div className={`fixed bottom-24 left-1/2 -translate-x-1/2 z-[60] px-5 py-3 rounded-full shadow-2xl text-sm font-medium text-white ${color} animate-bounce`} role="status">
      {message || (type === "success" ? "Berhasil!" : type === "error" ? "Terjadi kesalahan" : "Notifikasi")}
    </div>
  );
}


// ── ErrorBoundary ────────────────────────────────────────────────────────────
function AppErrorFallback({ error, debug }) {
  const hasHashRoute = Boolean(window.location.hash);
  const details = window.HiraRuntime ? window.HiraRuntime.formatErrorDetails(error) : (error && error.message ? error.message : "");
  return (
    <div className="min-h-screen flex items-center justify-center px-4 py-10 bg-[#0a0c16] text-stone-100">
      <div className="w-full max-w-xl rounded-3xl border border-white/10 bg-white/[0.04] p-7 shadow-2xl">
        <div className="text-4xl text-amber-400 mb-3">灯</div>
        <h1 className="font-display text-2xl mb-2">Terjadi kesalahan di frontend</h1>
        <p className="text-sm text-stone-400 leading-relaxed">UI berhenti merender sebagian. Coba muat ulang halaman. Jika kamu sedang membuka route hash, kamu juga bisa kembali ke home tanpa blank screen.</p>
        <div className="mt-5 flex flex-wrap gap-3">
          <button onClick={() => window.location.reload()} className="px-4 py-2 rounded-full bg-amber-400 text-[#0a0c16] text-sm font-medium">Muat ulang</button>
          {hasHashRoute && <button onClick={() => window.location.hash = "#/"} className="px-4 py-2 rounded-full border border-white/10 text-sm">Kembali ke home</button>}
        </div>
        {debug && details && (
          <details className="mt-5">
            <summary className="text-xs text-amber-300 cursor-pointer">Detail error</summary>
            <pre className="mt-2 whitespace-pre-wrap break-words text-[11px] text-stone-500">{details}</pre>
          </details>
        )}
      </div>
    </div>
  );
}

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }

  componentDidCatch(error, info) {
    console.error("React Error:", error, info);
    if (window.HiraRuntime) {
      window.HiraRuntime.emitGlobalError({
        message: error && error.message ? error.message : "React render error",
        stack: error && error.stack ? error.stack : "",
        info,
      }, "react.error-boundary");
    }
  }

  render() {
    if (!this.state.hasError) return this.props.children;
    return <AppErrorFallback error={this.state.error} debug={true} />;
  }
}

  window.HiraUI = {
    useTheme,
    EmptyState,
    SkeletonGrid,
    Toast,
    ErrorBoundary,
  };
})();
