/* ============================================================
   ONLYCLEAN — Shared UI components (app/components.jsx)
   ============================================================ */
const { useState, useEffect, useRef, createContext, useContext } = React;

/* ---------------- Icons (simple line icons) ---------------- */
/* brand outline icons (chat, clock) rendered inline so they inherit currentColor per section */
const Icon = ({ name, style, className }) => {
  const brand = (typeof window !== "undefined" && window.BRAND_ICONS) ? window.BRAND_ICONS[name] : null;
  if (brand) {
    const s = P_style(style);
    return <svg viewBox={brand.vb} className={className} style={{ width: 24, height: 24, ...s, color: s.color }} fill="none" dangerouslySetInnerHTML={{ __html: brand.inner }}></svg>;
  }
  const P = { fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" };
  const paths = {
    chevronRight: <path d="M9 18l6-6-6-6" />,
    chevronLeft: <path d="M15 18l-6-6 6-6" />,
    chevronDown: <path d="M6 9l6 6 6-6" />,
    play: <path d="M6 4l14 8-14 8V4z" fill="currentColor" stroke="none" />,
    dumbbell: <g><path d="M6.5 6.5l11 11" /><path d="M4 9l-1.5-1.5a1.5 1.5 0 0 1 0-2L5 3a1.5 1.5 0 0 1 2 0L8.5 4.5" /><path d="M15.5 19.5L17 21a1.5 1.5 0 0 0 2 0L21 19a1.5 1.5 0 0 0 0-2l-1.5-1.5" /></g>,
    calendar: <g><rect x="3" y="4.5" width="18" height="17" rx="3" /><path d="M3 9.5h18M8 2.5v4M16 2.5v4" /></g>,
    book: <path d="M4 4.5A2.5 2.5 0 0 1 6.5 2H20v17H6.5A2.5 2.5 0 0 0 4 21.5z" />,
    apple: <g><path d="M12 7c0-2 1.5-3.5 3.5-3.5" /><path d="M12 7c-3 0-5 2-5 5.5 0 4 2.5 8 5 8 1 0 1.5-.5 2.5-.5s1.5.5 2.5.5c2.5 0 5-4 5-8 0-3.5-2-5.5-5-5.5-1 0-1.5.5-2.5.5S13 7 12 7z" /></g>,
    heart: <path d="M12 20.5l-1.4-1.3C5.4 14.5 2 11.4 2 7.7 2 5 4.1 3 6.8 3c1.5 0 3 .7 3.9 1.9l1.3 1.6 1.3-1.6C14.2 3.7 15.7 3 17.2 3 19.9 3 22 5 22 7.7c0 3.7-3.4 6.8-8.6 11.5z" />,
    snowflake: <g><path d="M12 2v20M2 12h20M5 5l14 14M19 5L5 19" style={{ stroke: "rgb(233, 233, 233)" }} /></g>,
    flame: <path d="M12 22c4 0 7-2.8 7-6.5 0-3-2-5.5-3-7-1 1.5-2 2-3 2 .5-2-.5-4.5-3-6 .3 3-1.5 4.3-3 6.5-1 1.5-2 3-2 4.5C2 19.2 5 22 9 22z" />,
    hands: <g><path d="M7 11V4.5a1.5 1.5 0 0 1 3 0V10" /><path d="M10 10V3.5a1.5 1.5 0 0 1 3 0V10" /><path d="M13 10.5V5a1.5 1.5 0 0 1 3 0v7" /><path d="M16 8.5a1.5 1.5 0 0 1 3 0V14c0 4-2.5 7-6 7s-6-2-7-5l-2-4.5a1.5 1.5 0 0 1 2.6-1.5L7 13" /></g>,
    moon: <path d="M20 14.5A8 8 0 0 1 9.5 4 8 8 0 1 0 20 14.5z" />,
    clock: <g><circle cx="12" cy="12" r="9" /><path d="M12 7v5l3.5 2" /></g>,
    mail: <g><rect x="3" y="5" width="18" height="14" rx="2.5" /><path d="M3.5 7l8.5 6 8.5-6" /></g>,
    chat: <path d="M21 11.5a7.5 7.5 0 0 1-10.5 6.86L4 20l1.6-4.2A7.5 7.5 0 1 1 21 11.5z" />,
    instagram: <g><rect x="3" y="3" width="18" height="18" rx="5" /><circle cx="12" cy="12" r="4" /><circle cx="17.3" cy="6.7" r="1.1" fill="currentColor" stroke="none" /></g>,
    whatsapp: <g><path d="M3 21l1.65-4.8A8 8 0 1 1 7.8 19.3z" /><path d="M9 8.5c-.3 0-.6.1-.85.45-.25.35-.65.85-.65 1.7s.7 1.85.95 2.2c.25.35 1.55 2.45 3.8 3.35 1.85.75 2.25.65 2.65.6.4-.05 1.3-.5 1.5-1.05.2-.55.2-1 .15-1.05-.05-.05-.2-.1-.45-.25l-1.3-.65c-.2-.1-.35-.1-.5.1l-.65.85c-.15.2-.3.2-.55.1-.25-.1-1.05-.4-1.7-1.15-.5-.55-.85-1.2-.95-1.4-.1-.2 0-.35.1-.45l.4-.5c.1-.15.15-.25.2-.4.05-.15 0-.3-.05-.4l-.6-1.5c-.15-.4-.3-.4-.5-.4z" fill="currentColor" stroke="none" /></g>,
    lock: <g><rect x="4.5" y="10.5" width="15" height="10" rx="2.5" /><path d="M8 10.5V7.5a4 4 0 0 1 8 0v3" /></g>,
    user: <g><circle cx="12" cy="8" r="4" /><path d="M4 21c0-4 3.5-6 8-6s8 2 8 6" /></g>,
    logout: <g><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" /><path d="M16 17l5-5-5-5M21 12H9" /></g>,
    plus: <path d="M12 5v14M5 12h14" />,
    trash: <g><path d="M3 6h18M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" /></g>,
    edit: <g><path d="M12 20h9" /><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z" /></g>,
    copy: <g><rect x="9" y="9" width="12" height="12" rx="2" /><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" /></g>,
    x: <path d="M18 6L6 18M6 6l12 12" />,
    external: <g><path d="M14 4h6v6" /><path d="M20 4l-9 9" /><path d="M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5" /></g>,
    check: <path d="M20 6L9 17l-5-5" />,
    link: <g><path d="M10 13a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1.5 1.5" /><path d="M14 11a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1.5-1.5" /></g>,
    grid: <g><rect x="3" y="3" width="7" height="7" rx="1.5" /><rect x="14" y="3" width="7" height="7" rx="1.5" /><rect x="3" y="14" width="7" height="7" rx="1.5" /><rect x="14" y="14" width="7" height="7" rx="1.5" /></g>,
    bed: <g><path d="M3 18V8M3 12h13a4 4 0 0 1 4 4v2M3 18h18" /><circle cx="7.5" cy="10.5" r="1.5" /></g>
  };
  return (
    <svg viewBox="0 0 24 24" className={className} style={{ width: 24, height: 24, ...P_style(style) }} {...P}>
      {paths[name] || null}
    </svg>);

};
function P_style(s) {return s || {};}

/* recovery icons available as brand SVG vectors (recolored via CSS filter) */
const RECO_ICON_SRC = { snowflake: "assets/icon-frio.svg", flame: "assets/icon-calor.svg", hands: "assets/icon-fisio.svg" };
function RecoIcon({ name, className = "", style }) {
  const src = RECO_ICON_SRC[name];
  if (!src) return <Icon name={name} className={className} style={style} />;
  return <img src={src} alt="" className={`reco-img ${className}`} style={style} />;
}

/* day-type → icon + label */
const DAYTYPE = {
  high: { label: "High intensity", icon: null, cls: "high" },
  low: { label: "Low intensity", icon: null, cls: "low" },
  rest: { label: "Full rest", icon: "rest", cls: "rest" },
  empty: { label: "—", icon: null, cls: "muted" }
};

/* iconos disponibles para recuperaciones (badge en calendario + sección) */
const RECOVERY_ICONS = [
{ v: "snowflake", l: "Frío / Ice bath" },
{ v: "flame", l: "Calor / Sauna" },
{ v: "hands", l: "Fisioterapia" },
{ v: "heart", l: "General" },
{ v: "moon", l: "Descanso / Sueño" }];


/* ---------------- Pills & buttons ---------------- */
const Pill = ({ children, onClick, variant = "", className = "", type = "button", ...rest }) =>
<button type={type} className={`pill ${variant} ${className}`} onClick={onClick} {...rest}>{children}</button>;

const BackPill = ({ onClick, label = "Regresar" }) =>
<button className="back-pill" onClick={onClick}><Icon name="chevronLeft" /> {label}</button>;


/* ---------------- Phone frame ---------------- */
const Phone = ({ children }) => <div className="phone">{children}</div>;
const Screen = ({ children, className = "", innerRef, onScroll }) => <div ref={innerRef} onScroll={onScroll} className={`screen ${className}`}>{children}</div>;

/* ---------------- Video modal ---------------- */
function youTubeId(url) {
  try {
    const u = new URL(url);
    if (u.hostname.includes("youtu.be")) return u.pathname.slice(1).split("/")[0];
    if (u.hostname.includes("youtube.com")) {
      if (u.pathname.startsWith("/shorts/")) return u.pathname.split("/")[2];
      if (u.pathname.startsWith("/embed/")) return u.pathname.split("/")[2];
      const v = u.searchParams.get("v");
      if (v) return v;
    }
  } catch (e) {}
  return null;
}
function toEmbed(url) {
  if (!url) return null;
  const yt = youTubeId(url);
  if (yt) return "https://www.youtube-nocookie.com/embed/" + yt + "?rel=0&playsinline=1&modestbranding=1&autoplay=1";
  try {
    const u = new URL(url);
    if (u.hostname.includes("vimeo.com")) return "https://player.vimeo.com/video/" + u.pathname.split("/").filter(Boolean).pop() + "?autoplay=1";
  } catch (e) {}
  return url; // mp4 / other → use as-is in <video> fallback
}
const VideoModal = ({ url, title, onClose }) => {
  if (!url) return null;
  const embed = toEmbed(url);
  const isFile = /\.(mp4|webm|mov)(\?|$)/i.test(url);
  const isYouTube = !!youTubeId(url);
  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, zIndex: 60, background: "rgba(0,0,0,.78)", display: "flex", alignItems: "center", justifyContent: "center", padding: 18 }}>
      <div onClick={(e) => e.stopPropagation()} style={{ width: "100%", maxWidth: 420, background: "#000", borderRadius: 20, overflow: "hidden", boxShadow: "0 30px 80px -20px rgba(0,0,0,.8)" }}>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "12px 14px", background: "#111", color: "#fff" }}>
          <span style={{ fontSize: 13, fontWeight: 600, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{title || "Video del ejercicio"}</span>
          <button onClick={onClose} style={{ background: "none", border: "none", color: "#fff", display: "flex" }}><Icon name="x" style={{ width: 20, height: 20 }} /></button>
        </div>
        <div style={{ aspectRatio: isFile ? "16/9" : "9/16", maxHeight: "70vh", background: "#000" }}>
          {isFile ?
          <video src={url} controls autoPlay style={{ width: "100%", height: "100%" }} /> :
          <iframe src={embed} allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowFullScreen style={{ width: "100%", height: "100%", border: "none" }} />}
        </div>
        {!isFile &&
        <a href={url} target="_blank" rel="noopener noreferrer" style={{ display: "flex", alignItems: "center", justifyContent: "center", gap: 7, padding: "13px 14px", background: "#111", color: "#fff", fontSize: 13.5, fontWeight: 600, borderTop: "1px solid #222" }}>
          {isYouTube ? "Abrir en YouTube" : "Abrir el video"} <Icon name="external" style={{ width: 15, height: 15 }} />
        </a>}
      </div>
    </div>);

};

/* ---------------- Toast ---------------- */
const ToastCtx = createContext(() => {});
const useToast = () => useContext(ToastCtx);
const ToastHost = ({ children }) => {
  const [msg, setMsg] = useState(null);
  const show = (m) => {setMsg(m);setTimeout(() => setMsg(null), 2200);};
  return (
    <ToastCtx.Provider value={show}>
      {children}
      {msg &&
      <div className="fade-in" style={{ position: "fixed", left: "50%", bottom: 28, transform: "translateX(-50%)", zIndex: 80, background: "#232323", color: "#fff", padding: "11px 20px", borderRadius: 999, fontSize: 13.5, fontWeight: 500, boxShadow: "0 12px 30px -10px rgba(0,0,0,.5)" }}>{msg}</div>
      }
    </ToastCtx.Provider>);

};

/* ---------------- Confirm dialog ---------------- */
const Confirm = ({ open, text, onYes, onNo }) => {
  if (!open) return null;
  return (
    <div style={{ position: "fixed", inset: 0, zIndex: 70, background: "rgba(0,0,0,.5)", display: "flex", alignItems: "center", justifyContent: "center", padding: 22 }}>
      <div className="card fade-in" style={{ maxWidth: 340, width: "100%" }}>
        <p style={{ fontSize: 15.5, fontWeight: 500, lineHeight: 1.4 }}>{text}</p>
        <div style={{ display: "flex", gap: 10, marginTop: 18 }}>
          <Pill variant="ghost" className="block" onClick={onNo}>Cancelar</Pill>
          <Pill variant="coral" className="block" onClick={onYes}>Eliminar</Pill>
        </div>
      </div>
    </div>);

};

/* ---------------- Photo upload (file → downscaled data URL) ---------------- */
function PhotoUpload({ value, onChange, label = "Foto de perfil" }) {
  const inputRef = useRef(null);
  const [busy, setBusy] = useState(false);

  function pick() { inputRef.current && inputRef.current.click(); }

  function onFile(e) {
    const file = e.target.files && e.target.files[0];
    if (!file) return;
    setBusy(true);
    const reader = new FileReader();
    reader.onload = () => {
      const img = new Image();
      img.onload = () => {
        // downscale to max 480px, export as JPEG to keep localStorage small
        const max = 480;
        let { width, height } = img;
        if (width > height && width > max) { height = Math.round(height * max / width); width = max; }
        else if (height > max) { width = Math.round(width * max / height); height = max; }
        const cv = document.createElement("canvas");
        cv.width = width; cv.height = height;
        cv.getContext("2d").drawImage(img, 0, 0, width, height);
        onChange(cv.toDataURL("image/jpeg", 0.82));
        setBusy(false);
      };
      img.onerror = () => setBusy(false);
      img.src = reader.result;
    };
    reader.onerror = () => setBusy(false);
    reader.readAsDataURL(file);
    e.target.value = "";
  }

  return (
    <div className="field">
      <label>{label}</label>
      <div className="photo-up">
        <span className="photo-up-preview">{value ? <img src={value} alt="" /> : <Icon name="user" style={{ width: 22, height: 22, color: "#b3b3b3" }} />}</span>
        <div className="photo-up-actions">
          <button type="button" className="pill ghost sm" onClick={pick}>{busy ? "Procesando…" : (value ? "Cambiar foto" : "Subir foto")}</button>
          {value && <button type="button" className="photo-up-remove" onClick={() => onChange("")}>Quitar</button>}
          <div className="photo-up-hint">Sube una imagen desde tu teléfono o PC.</div>
        </div>
        <input ref={inputRef} type="file" accept="image/*" onChange={onFile} style={{ display: "none" }} />
      </div>
    </div>
  );
}

/* metric icons for dashboards: prefer brand vector glyphs (rendered white), else line icon */
const METRIC_BRAND = {
  calendar: "assets/icon-calendar.svg",
  dumbbell: "assets/icon-metodo.svg",
  snowflake: "assets/icon-recuperacion.svg",
  apple: "assets/icon-alimentacion.svg",
};
function MetricIcon({ name }) {
  if (METRIC_BRAND[name]) return <img className="metric-glyph" src={METRIC_BRAND[name]} alt="" />;
  return <Icon name={name} style={{ width: 20, height: 20 }} />;
}

Object.assign(window, { Icon, RecoIcon, MetricIcon, DAYTYPE, RECOVERY_ICONS, Pill, BackPill, Phone, Screen, VideoModal, toEmbed, ToastHost, useToast, Confirm, PhotoUpload });