/* portfolio-ui.jsx — Icons + small shared primitives */

const { useEffect, useRef, useState } = React;

// =========================================================
// ICONS — inline SVGs, single-stroke geometric style
// =========================================================
const Icon = ({ name, size = 16, stroke = 1.6 }) => {
  const common = {
    width: size, height: size,
    viewBox: "0 0 24 24",
    fill: "none", stroke: "currentColor",
    strokeWidth: stroke,
    strokeLinecap: "round", strokeLinejoin: "round",
  };
  switch (name) {
    case "github": return <svg {...common}><path d="M9 19c-4 1.5-4-2-6-2.5M15 21v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 19 3.5a5.07 5.07 0 0 0-.09-3.77S17.59 0 15 1.7a13.38 13.38 0 0 0-7 0C5.41 0 4.09.23 4.09.23A5.07 5.07 0 0 0 4 4a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 8 17.13V21" /></svg>;
    case "linkedin": return <svg {...common}><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-4 0v7h-4v-7a6 6 0 0 1 6-6z"/><rect x="2" y="9" width="4" height="12"/><circle cx="4" cy="4" r="2"/></svg>;
    case "mail": return <svg {...common}><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-10 6L2 7"/></svg>;
    case "phone": return <svg {...common}><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.37 1.9.72 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.35 1.85.59 2.81.72A2 2 0 0 1 22 16.92z"/></svg>;
    case "location": return <svg {...common}><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>;
    case "external": return <svg {...common}><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6"/><path d="m10 14 11-11"/></svg>;
    case "download": return <svg {...common}><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/><path d="M12 15V3"/></svg>;
    case "arrow-right": return <svg {...common}><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>;
    case "arrow-down": return <svg {...common}><path d="M12 5v14"/><path d="m19 12-7 7-7-7"/></svg>;
    case "close": return <svg {...common}><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>;
    case "check": return <svg {...common}><path d="M20 6 9 17l-5-5"/></svg>;
    case "plus": return <svg {...common}><path d="M12 5v14"/><path d="M5 12h14"/></svg>;
    case "edit": return <svg {...common}><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5z"/></svg>;
    case "trash": return <svg {...common}><path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>;
    case "drag": return <svg {...common}><circle cx="9" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="15" cy="18" r="1"/></svg>;
    case "settings": return <svg {...common}><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>;
    case "sun": return <svg {...common}><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>;
    case "moon": return <svg {...common}><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>;
    case "blueprint": return <svg {...common}><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 3v18M14 14l3 3M14 17h3v-3"/></svg>;
    case "compass": return <svg {...common}><circle cx="12" cy="12" r="10"/><path d="m16 8-2 6-6 2 2-6 6-2z"/></svg>;
    case "spark": return <svg {...common}><path d="M12 3v3M12 18v3M3 12h3M18 12h3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1"/><circle cx="12" cy="12" r="2.5"/></svg>;
    case "shield": return <svg {...common}><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>;
    case "database": return <svg {...common}><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v6c0 1.66 4 3 9 3s9-1.34 9-3V5"/><path d="M3 11v6c0 1.66 4 3 9 3s9-1.34 9-3v-6"/></svg>;
    case "code": return <svg {...common}><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>;
    case "bolt": return <svg {...common}><path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z"/></svg>;
    case "chart": return <svg {...common}><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/><line x1="3" y1="20" x2="21" y2="20"/></svg>;
    case "layers": return <svg {...common}><polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></svg>;
    case "stack": return <svg {...common}><rect x="3" y="3" width="18" height="6" rx="1"/><rect x="3" y="15" width="18" height="6" rx="1"/><line x1="7" y1="6" x2="7.01" y2="6"/><line x1="7" y1="18" x2="7.01" y2="18"/></svg>;
    case "globe": return <svg {...common}><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>;
    case "play": return <svg {...common}><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg>;
    case "file": return <svg {...common}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>;
    case "image": return <svg {...common}><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>;
    case "send": return <svg {...common}><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>;
    case "copy": return <svg {...common}><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>;
    case "share": return <svg {...common}><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.6" y1="13.5" x2="15.4" y2="17.5"/><line x1="15.4" y1="6.5" x2="8.6" y2="10.5"/></svg>;
    case "menu": return <svg {...common}><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>;
    default: return null;
  }
};

// =========================================================
// Section wrapper with eyebrow + title
// =========================================================
const Section = ({ id, eyebrow, title, italic, sub, children, head = true, action }) => (
  <section id={id}>
    <div className="container">
      {head && (
        <div className="section-head">
          <div>
            {eyebrow && <div className="section-eyebrow">{eyebrow}</div>}
            <h2 className="section-title">
              {italic
                ? <>{title} <span className="it">{italic}</span></>
                : title}
            </h2>
            {sub && <p className="section-sub">{sub}</p>}
          </div>
          {action}
        </div>
      )}
      {children}
    </div>
  </section>
);

// =========================================================
// Typing word rotator (for hero)
// =========================================================
const Typewriter = ({ words = [], speed = 80, pause = 1600 }) => {
  const [i, setI] = useState(0);
  const [out, setOut] = useState("");
  const [del, setDel] = useState(false);
  useEffect(() => {
    if (!words.length) return;
    const cur = words[i % words.length];
    let t;
    if (!del && out.length < cur.length) {
      t = setTimeout(() => setOut(cur.slice(0, out.length + 1)), speed);
    } else if (!del && out.length === cur.length) {
      t = setTimeout(() => setDel(true), pause);
    } else if (del && out.length > 0) {
      t = setTimeout(() => setOut(cur.slice(0, out.length - 1)), speed / 2);
    } else if (del && out.length === 0) {
      setDel(false);
      setI((v) => v + 1);
    }
    return () => clearTimeout(t);
  }, [out, del, i, words, speed, pause]);
  return <span className="hero-typing">{out}</span>;
};

// =========================================================
// Toast (light global notification)
// =========================================================
const ToastContext = React.createContext({ show: () => {} });
const ToastProvider = ({ children }) => {
  const [msg, setMsg] = useState(null);
  const tRef = useRef();
  const show = (text) => {
    setMsg(text);
    clearTimeout(tRef.current);
    tRef.current = setTimeout(() => setMsg(null), 2200);
  };
  return (
    <ToastContext.Provider value={{ show }}>
      {children}
      <div className={"toast" + (msg ? " show" : "")}>
        <span className="dot"></span>
        <span>{msg}</span>
      </div>
    </ToastContext.Provider>
  );
};

// =========================================================
// Editable wrapper — when admin mode, hovering shows an Edit pill
// =========================================================
const Editable = ({ onEdit, label = "Edit", children, className = "" }) => (
  <div
    className={"editable " + className}
    onClick={(e) => {
      if (!document.documentElement.classList.contains("is-admin")) return;
      e.stopPropagation();
      onEdit && onEdit();
    }}
  >
    <span className="edit-pill"><Icon name="edit" size={10} /> {label}</span>
    {children}
  </div>
);

// =========================================================
// Project art placeholder (no thumbnail uploaded)
// =========================================================
const PlaceholderArt = ({ seed = "" }) => {
  const hash = [...(seed || "x")].reduce((a, c) => a + c.charCodeAt(0), 0);
  const angle = (hash * 23) % 360;
  return (
    <div className="placeholder-art" style={{
      background:
        `radial-gradient(60% 80% at ${20 + (hash % 60)}% ${20 + (hash * 7 % 60)}%, var(--accent-soft), transparent 60%),
         linear-gradient(${angle}deg, var(--surface-2), var(--surface-3))`
    }}>
      <svg width="120" height="120" viewBox="0 0 120 120" fill="none">
        <circle cx="60" cy="60" r="36" stroke="currentColor" strokeWidth="1" strokeDasharray="4 6" opacity="0.4" />
        <circle cx="60" cy="60" r="56" stroke="currentColor" strokeWidth="0.5" strokeDasharray="2 6" opacity="0.25" />
        <circle cx="60" cy="60" r="16" stroke="currentColor" strokeWidth="1.5" opacity="0.7" />
        <circle cx="60" cy="60" r="3" fill="currentColor" />
      </svg>
    </div>
  );
};

Object.assign(window, { Icon, Section, Typewriter, ToastProvider, ToastContext, Editable, PlaceholderArt });
