/* global React, Icon */
/* Overlays: Modal, Drawer, Popover, Toast, Empty, Loading, Error, Skeleton */

const { useState, useEffect, useRef, useCallback } = React;

function Modal({ open, onClose, title, eyebrow, children, footer, width = 520 }) {
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => e.key === "Escape" && onClose && onClose();
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div onClick={onClose}
      style={{
        position: "fixed", inset: 0, background: "rgba(10,10,10,0.55)",
        zIndex: 200, display: "flex", alignItems: "center", justifyContent: "center", padding: 24,
        animation: "fadeIn 200ms ease",
      }}
    >
      <div onClick={(e) => e.stopPropagation()}
        style={{
          background: "var(--bg)", color: "var(--ink)", maxWidth: width, width: "100%",
          border: "1px solid var(--ink)", borderRadius: "var(--r-sharp)",
          animation: "popIn 220ms cubic-bezier(.2,.7,.2,1)", maxHeight: "85vh", overflow: "auto",
        }} className="scroll"
      >
        <div className="row between" style={{ padding: "20px 24px 0", alignItems: "flex-start" }}>
          {eyebrow && <span className="eyebrow">{eyebrow}</span>}
          <button onClick={onClose} aria-label="Close"
            style={{ marginLeft: "auto", border: 0, background: "transparent", color: "var(--ink-2)", cursor: "pointer", padding: 4 }}>
            <Icon.X size={18}/>
          </button>
        </div>
        <div style={{ padding: "12px 24px 24px" }}>
          {title && <h2 style={{ fontSize: 24, fontWeight: 600, letterSpacing: "-0.02em", lineHeight: 1.15, margin: "0 0 12px" }}>{title}</h2>}
          {children}
        </div>
        {footer && (
          <div style={{ borderTop: "1px solid var(--line)", padding: "16px 24px", display: "flex", justifyContent: "flex-end", gap: 8 }}>
            {footer}
          </div>
        )}
      </div>
    </div>
  );
}

function Drawer({ open, onClose, title, eyebrow, children, footer, width = 520 }) {
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => e.key === "Escape" && onClose && onClose();
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div onClick={onClose}
      style={{ position: "fixed", inset: 0, background: "rgba(10,10,10,0.4)", zIndex: 190, animation: "fadeIn 220ms ease" }}>
      <div onClick={(e) => e.stopPropagation()}
        style={{
          position: "absolute", right: 0, top: 0, bottom: 0, width, maxWidth: "94vw",
          background: "var(--bg)", borderLeft: "1px solid var(--line-2)",
          display: "flex", flexDirection: "column",
          animation: "slideInR 280ms cubic-bezier(.2,.7,.2,1)",
        }}>
        <div style={{ padding: "20px 28px", borderBottom: "1px solid var(--line)" }}>
          {eyebrow && <div style={{ marginBottom: 8 }}><span className="eyebrow">{eyebrow}</span></div>}
          <div className="row between gap-12" style={{ alignItems: "flex-start" }}>
            <h3 style={{ fontSize: 22, fontWeight: 600, letterSpacing: "-0.018em", margin: 0, lineHeight: 1.2 }}>{title}</h3>
            <button onClick={onClose} aria-label="Close" style={{ border: 0, background: "transparent", color: "var(--ink-2)", cursor: "pointer", padding: 4 }}>
              <Icon.X size={18}/>
            </button>
          </div>
        </div>
        <div className="scroll" style={{ flex: 1, overflow: "auto", padding: 28 }}>{children}</div>
        {footer && (
          <div style={{ borderTop: "1px solid var(--line)", padding: "16px 28px", display: "flex", justifyContent: "flex-end", gap: 8 }}>
            {footer}
          </div>
        )}
      </div>
    </div>
  );
}

function Popover({ trigger, children, align = "right" }) {
  const [open, setOpen] = useState(false);
  const ref = useRef();
  useEffect(() => {
    if (!open) return;
    const onClick = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    setTimeout(() => document.addEventListener("click", onClick), 0);
    return () => document.removeEventListener("click", onClick);
  }, [open]);
  return (
    <div ref={ref} style={{ position: "relative", display: "inline-block" }}>
      <span onClick={() => setOpen(!open)} style={{ display: "inline-block" }}>{trigger}</span>
      {open && (
        <div style={{
          position: "absolute", top: "calc(100% + 6px)",
          [align]: 0, minWidth: 220, zIndex: 50,
          background: "var(--bg)", border: "1px solid var(--line-2)", borderRadius: "var(--r-sharp)",
          padding: 6, animation: "popIn 180ms cubic-bezier(.2,.7,.2,1)",
        }}>
          {typeof children === "function" ? children({ close: () => setOpen(false) }) : children}
        </div>
      )}
    </div>
  );
}

function PopoverItem({ icon, label, shortcut, danger, onClick }) {
  return (
    <button onClick={onClick} style={{
      width: "100%", display: "flex", alignItems: "center", gap: 10,
      padding: "8px 10px", border: 0, background: "transparent",
      color: danger ? "var(--neg)" : "var(--ink)",
      fontFamily: "var(--sans)", fontSize: 13, cursor: "pointer", textAlign: "left",
      borderRadius: 2, transition: "background 150ms ease",
    }}
    onMouseEnter={(e) => e.currentTarget.style.background = "var(--bg-2)"}
    onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}>
      {icon && <span style={{ color: danger ? "var(--neg)" : "var(--ink-2)", display: "inline-flex" }}>{icon}</span>}
      <span style={{ flex: 1 }}>{label}</span>
      {shortcut && <span className="mono" style={{ color: "var(--ink-3)", fontSize: 10 }}>{shortcut}</span>}
    </button>
  );
}

/* ---------- Toasts ---------- */
const ToastCtx = React.createContext(null);

function ToastHost({ children }) {
  const [items, setItems] = useState([]);
  const push = useCallback((t) => {
    const id = Math.random().toString(36).slice(2);
    setItems((prev) => [...prev, { id, ...t }]);
    setTimeout(() => setItems((prev) => prev.filter(x => x.id !== id)), t.duration || 3500);
  }, []);
  return (
    <ToastCtx.Provider value={push}>
      {children}
      <div style={{
        position: "fixed", bottom: 24, right: 24, zIndex: 300,
        display: "flex", flexDirection: "column", gap: 8, alignItems: "flex-end",
        pointerEvents: "none",
      }}>
        {items.map(t => (
          <div key={t.id} style={{
            pointerEvents: "auto",
            background: "var(--ink)", color: "var(--bg)",
            padding: "12px 16px 12px 14px", borderRadius: "var(--r-sharp)",
            display: "flex", alignItems: "center", gap: 10, minWidth: 240, maxWidth: 380,
            animation: "slideInR 260ms cubic-bezier(.2,.7,.2,1)",
            borderLeft: t.tone === "pos" ? "3px solid var(--pos)" : t.tone === "neg" ? "3px solid var(--neg)" : "3px solid var(--grad-4)",
          }}>
            <div className="col" style={{ flex: 1 }}>
              {t.title && <div style={{ fontSize: 13, fontWeight: 600 }}>{t.title}</div>}
              {t.body && <div style={{ fontSize: 12, opacity: 0.75, marginTop: 2 }}>{t.body}</div>}
            </div>
            {t.action && (
              <button onClick={t.action.onClick} style={{
                border: 0, background: "transparent", color: "var(--bg)",
                fontFamily: "var(--mono)", fontSize: 10, fontWeight: 700,
                letterSpacing: "0.08em", textTransform: "uppercase", cursor: "pointer",
              }}>{t.action.label}</button>
            )}
          </div>
        ))}
      </div>
    </ToastCtx.Provider>
  );
}
function useToast() { return React.useContext(ToastCtx); }

/* ---------- Empty / Loading / Error states ---------- */
function EmptyState({ eyebrow = "Nothing yet", title, body, action, illustration }) {
  return (
    <div className="col" style={{ alignItems: "center", textAlign: "center", padding: "64px 24px", maxWidth: 520, margin: "0 auto" }}>
      {illustration || (
        <div style={{
          width: 96, height: 96, borderRadius: "var(--r-sharp)",
          background: "var(--ph-teal)", marginBottom: 28,
          position: "relative", overflow: "hidden",
        }}>
          <div style={{ position: "absolute", inset: 0, background: "var(--ph-overlay)" }}/>
        </div>
      )}
      <span className="eyebrow">{eyebrow}</span>
      <h3 style={{ fontSize: 28, fontWeight: 600, letterSpacing: "-0.025em", margin: "16px 0 8px", lineHeight: 1.1 }}>{title}</h3>
      {body && <p style={{ fontSize: 15, color: "var(--ink-2)", lineHeight: 1.55, margin: 0, maxWidth: 380 }}>{body}</p>}
      {action && <div style={{ marginTop: 24 }}>{action}</div>}
    </div>
  );
}

function LoadingState({ label = "Loading", body }) {
  return (
    <div className="col" style={{ alignItems: "center", textAlign: "center", padding: "64px 24px" }}>
      <div style={{ display: "inline-flex", marginBottom: 20 }}><Spinner size={28}/></div>
      <span className="eyebrow">{label}</span>
      {body && <p style={{ marginTop: 12, color: "var(--ink-2)", fontSize: 14 }}>{body}</p>}
    </div>
  );
}

function ErrorState({ title = "Something went wrong", body, action }) {
  return (
    <div className="col" style={{ alignItems: "center", textAlign: "center", padding: "64px 24px", maxWidth: 520, margin: "0 auto" }}>
      <div style={{
        width: 64, height: 64, borderRadius: "var(--r-sharp)",
        background: "var(--neg-bg)", color: "var(--neg)",
        display: "inline-flex", alignItems: "center", justifyContent: "center",
        marginBottom: 24,
      }}>
        <Icon.Alert size={28}/>
      </div>
      <span className="eyebrow no-bar" style={{ color: "var(--neg)" }}>Error</span>
      <h3 style={{ fontSize: 24, fontWeight: 600, letterSpacing: "-0.022em", margin: "12px 0 8px" }}>{title}</h3>
      {body && <p style={{ fontSize: 14, color: "var(--ink-2)", margin: 0 }}>{body}</p>}
      {action && <div style={{ marginTop: 20 }}>{action}</div>}
    </div>
  );
}

function Skeleton({ w = "100%", h = 14, radius = 2, circle, style }) {
  return (
    <span style={{
      display: "block", width: circle ? h : w, height: h,
      background: "linear-gradient(90deg, var(--bg-2), var(--bg-3), var(--bg-2))",
      backgroundSize: "200% 100%",
      animation: "shimmer 1.4s linear infinite",
      borderRadius: circle ? 999 : radius, ...style,
    }}/>
  );
}

/* ---------- ErrorBoundary ---------- */
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) {
    if (this.props.onError) this.props.onError(error, info);
  }
  reset = () => this.setState({ hasError: false, error: null });
  render() {
    if (this.state.hasError) {
      if (this.props.fallback) {
        return typeof this.props.fallback === "function"
          ? this.props.fallback({ error: this.state.error, reset: this.reset })
          : this.props.fallback;
      }
      return (
        <div style={{ padding: 24, border: "1px solid var(--neg)", background: "var(--neg-bg)", borderRadius: 2 }}>
          <div className="eyebrow no-bar" style={{ color: "var(--neg)", marginBottom: 8 }}>Component error</div>
          <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 6 }}>{String(this.state.error?.message || this.state.error || "Something went wrong")}</div>
          <button onClick={this.reset} style={{ background: "var(--ink)", color: "var(--bg)", border: 0, padding: "6px 12px", borderRadius: 2, fontFamily: "var(--mono)", fontSize: 10, letterSpacing: "0.08em", textTransform: "uppercase", cursor: "pointer" }}>Try again</button>
        </div>
      );
    }
    return this.props.children;
  }
}

/* ---------- Banner ---------- */
function Banner({ tone = "info", title, body, action, onClose }) {
  const tones = {
    info: { color: "var(--info)", bg: "var(--info-bg)" },
    pos: { color: "var(--pos)", bg: "var(--pos-bg)" },
    warn: { color: "var(--warn)", bg: "var(--warn-bg)" },
    neg: { color: "var(--neg)", bg: "var(--neg-bg)" },
    grad: { color: "white", bg: "var(--brand-grad-band)" },
  };
  const t = tones[tone];
  return (
    <div style={{
      padding: "14px 16px", background: t.bg, color: tone === "grad" ? "white" : "var(--ink)",
      borderRadius: "var(--r-sharp)", display: "flex", gap: 12, alignItems: "flex-start",
      borderLeft: tone !== "grad" ? `3px solid ${t.color}` : "none",
    }}>
      <span style={{ color: tone === "grad" ? "white" : t.color, marginTop: 2 }}>
        <Icon.Info size={16}/>
      </span>
      <div className="col gap-4" style={{ flex: 1 }}>
        {title && <div style={{ fontSize: 14, fontWeight: 600 }}>{title}</div>}
        {body && <div style={{ fontSize: 13, opacity: tone === "grad" ? 0.9 : 1, color: tone === "grad" ? "white" : "var(--ink-2)" }}>{body}</div>}
      </div>
      {action}
      {onClose && (
        <button onClick={onClose} style={{ border: 0, background: "transparent", color: "inherit", cursor: "pointer", padding: 2 }}>
          <Icon.X size={14}/>
        </button>
      )}
    </div>
  );
}

Object.assign(window, { Modal, Drawer, Popover, PopoverItem, ToastHost, useToast, EmptyState, LoadingState, ErrorState, Skeleton, Banner, ErrorBoundary });
