/* global React, ReactDOM, PROTOCOL */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* ---------- Helpers ---------- */
function classNames(...args) { return args.filter(Boolean).join(" "); }

function Collapse({ open, children }) {
  return (
    <div className={classNames("collapse", open && "open")} aria-hidden={!open}>
      <div>{children}</div>
    </div>
  );
}

/* ---------- Decálogo ---------- */
function Decalogo({ rows }) {
  const [open, setOpen] = useState(() => new Set(["01"]));
  const toggle = (n) => {
    const next = new Set(open);
    next.has(n) ? next.delete(n) : next.add(n);
    setOpen(next);
  };
  return (
    <div className="decalogo">
      {rows.map(r => {
        const isOpen = open.has(r.n);
        return (
          <div key={r.n} className="dec-row" data-open={isOpen}>
            <button className="dec-head" onClick={() => toggle(r.n)} aria-expanded={isOpen}>
              <span className="dec-num">{r.n}</span>
              <span className="dec-conducta">{r.conducta}</span>
              <span className="dec-toggle" aria-hidden="true">+</span>
            </button>
            <Collapse open={isOpen}>
              <div className="dec-body">
                <div></div>
                <div>
                  <p className="dec-desc">{r.desc}</p>
                  <div className="dec-ej">{r.ej}</div>
                </div>
              </div>
            </Collapse>
          </div>
        );
      })}
    </div>
  );
}

/* ---------- Competencias ---------- */
function Competencias({ items }) {
  return (
    <div className="competencias">
      {items.map((it, i) => (
        <article className="comp-card" key={i}>
          <h4 className="comp-title">{it.title}</h4>
          <p className="comp-desc">{it.desc}</p>
          <ul className="comp-practica">
            {it.practica.map((p, j) => <li key={j}>{p}</li>)}
          </ul>
          <div className="dialog-pair">
            <div className="dialog-line di">
              <span className="tag">Di</span>
              <span className="text">{it.di}</span>
            </div>
            <div className="dialog-line evita">
              <span className="tag">En vez de</span>
              <span className="text">{it.evita}</span>
            </div>
          </div>
        </article>
      ))}
    </div>
  );
}

/* ---------- Roles ---------- */
function Roles({ roles }) {
  const [active, setActive] = useState(roles[0].id);
  const role = roles.find(r => r.id === active) || roles[0];
  return (
    <div>
      <div className="roles-tabs" role="tablist">
        {roles.map(r => (
          <button
            key={r.id}
            role="tab"
            aria-selected={active === r.id}
            className={classNames("role-tab", active === r.id && "active")}
            onClick={() => setActive(r.id)}
          >
            {r.name}
          </button>
        ))}
      </div>
      <p className="role-mission">{role.mission}</p>
      <Behaviors items={role.behaviors} key={role.id} />
    </div>
  );
}

function Behaviors({ items }) {
  const [open, setOpen] = useState(() => new Set([0]));
  const toggle = (i) => {
    const n = new Set(open);
    n.has(i) ? n.delete(i) : n.add(i);
    setOpen(n);
  };
  return (
    <div className="behaviors">
      {items.map((b, i) => {
        const isOpen = open.has(i);
        const num = String(i + 1).padStart(2, "0");
        return (
          <div className="beh" key={i} data-open={isOpen}>
            <button className="beh-head" onClick={() => toggle(i)} aria-expanded={isOpen}>
              <span className="beh-num">{num}</span>
              <span className="beh-title">{b.title}</span>
              <span className="beh-toggle">
                <span>{isOpen ? "Cerrar" : "Ver scripts"}</span>
                <span className="beh-chev" aria-hidden="true"></span>
              </span>
            </button>
            <Collapse open={isOpen}>
              <div className="beh-body">
                <ul className="beh-bullets">
                  {b.bullets.map((x, j) => <li key={j}>{x}</li>)}
                </ul>
                <div className="beh-scripts">
                  {b.scripts.map((s, j) => <div className="script" key={j}>{s}</div>)}
                </div>
              </div>
            </Collapse>
          </div>
        );
      })}
    </div>
  );
}

/* ---------- Moments ---------- */
function Moments({ moments }) {
  return (
    <div className="moments">
      {moments.map((m, i) => (
        <article className="moment" key={m.id}>
          <div className="moment-step">
            {String(i + 1).padStart(2, "0")}
            <small>Momento</small>
          </div>
          <div>
            <h4 className="moment-name">{m.name}</h4>
            <p className="moment-obj">{m.objective}</p>
            <div className="moment-cols">
              <div className="moment-col">
                <h5>Estándares</h5>
                <ul>{m.standards.map((x, j) => <li key={j}>{x}</li>)}</ul>
              </div>
              <div className="moment-col do">
                <h5>Frases sugeridas</h5>
                <ul>{m.say.map((x, j) => <li key={j}>{x}</li>)}</ul>
              </div>
              <div className="moment-col avoid">
                <h5>Evitar</h5>
                <ul>{m.avoid.map((x, j) => <li key={j}>{x}</li>)}</ul>
              </div>
            </div>
          </div>
        </article>
      ))}
    </div>
  );
}

/* ---------- Situations ---------- */
function Situations({ situations }) {
  const [open, setOpen] = useState(() => new Set([situations[0].id]));
  const toggle = (id) => {
    const n = new Set(open);
    n.has(id) ? n.delete(id) : n.add(id);
    setOpen(n);
  };
  return (
    <div className="sits">
      {situations.map((s, i) => {
        const isOpen = open.has(s.id);
        return (
          <div className="sit" key={s.id} data-open={isOpen}>
            <button className="sit-head" onClick={() => toggle(s.id)} aria-expanded={isOpen}>
              <span className="sit-marker"></span>
              <span className="sit-name">7.{i + 1} · {s.name}</span>
              <span className="sit-meta">{isOpen ? "Cerrar —" : `${s.steps.length} pasos +`}</span>
            </button>
            <Collapse open={isOpen}>
              <div className="sit-body">
                <div className="sit-steps">
                  {s.steps.map((st, j) => (
                    <div className="sit-step" key={j}>
                      <h6>
                        <span className="num">{j + 1}.</span>
                        <span>{st.title}</span>
                      </h6>
                      <div className="lines">
                        {st.lines.map((l, k) => (
                          <div className="script" key={k}>{l}</div>
                        ))}
                      </div>
                    </div>
                  ))}
                </div>
                <div className="sit-avoid">
                  <h6>Evitar</h6>
                  <ul>{s.avoid.map((a, j) => <li key={j}>{a}</li>)}</ul>
                </div>
              </div>
            </Collapse>
          </div>
        );
      })}
    </div>
  );
}

/* ---------- Communication + Channels ---------- */
function Comm({ columns }) {
  return (
    <div className="comm-cols">
      <div className="comm-col verbal">
        <h5>Lenguaje verbal</h5>
        <ul>{columns.verbal.map((x, i) => <li key={i}>{x}</li>)}</ul>
      </div>
      <div className="comm-col noverbal">
        <h5>Lenguaje no verbal</h5>
        <ul>{columns.noverbal.map((x, i) => <li key={i}>{x}</li>)}</ul>
      </div>
      <div className="comm-col evita">
        <h5>Evitar</h5>
        <ul>{columns.evita.map((x, i) => <li key={i}>{x}</li>)}</ul>
      </div>
    </div>
  );
}

function Channels({ rows, intro }) {
  return (
    <div>
      <p className="section-body" style={{ maxWidth: "60ch" }}>{intro}</p>
      <div className="channels">
        {rows.map((r, i) => (
          <div className="ch-row" key={i}>
            <div className="ch-name"><span className="dot"></span>{r.canal}</div>
            <div className="ch-std">{r.estandar}</div>
            <div className="ch-ej">{r.ej}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ---------- Ideal ---------- */
function Ideal({ steps, closer }) {
  return (
    <div>
      <div className="ideal">
        {steps.map((s, i) => <div className="ideal-step" key={i}>{s}</div>)}
      </div>
      <div className="ideal-closer">{closer}</div>
    </div>
  );
}

/* ---------- Section dispatcher ---------- */
function SectionRenderer({ s }) {
  if (s.kind === "decalogo") {
    return (
      <div className="section full">
        <h3 className="section-title"><span className="section-num">{s.id}</span>{s.title}</h3>
        <Decalogo rows={s.rows} />
      </div>
    );
  }
  if (s.kind === "promise") {
    return (
      <div className="section">
        <h3 className="section-title"><span className="section-num">{s.id}</span>{s.title}</h3>
        <blockquote className="promise">
          <p className="promise-text">“{s.body}”</p>
          <span className="promise-cite">Promesa de marca</span>
        </blockquote>
      </div>
    );
  }
  if (s.kind === "competencias") {
    return (
      <div className="section full">
        <h3 className="section-title"><span className="section-num">{s.id}</span>{s.title}</h3>
        <Competencias items={s.items} />
      </div>
    );
  }
  if (s.kind === "roles") {
    return (
      <div className="section full">
        <Roles roles={s.roles} />
      </div>
    );
  }
  if (s.kind === "moments") {
    return (
      <div className="section full">
        <Moments moments={s.moments} />
      </div>
    );
  }
  if (s.kind === "situations") {
    return (
      <div className="section full">
        <Situations situations={s.situations} />
      </div>
    );
  }
  if (s.kind === "comm") {
    return (
      <div className="section full">
        <h3 className="section-title"><span className="section-num">{s.id}</span>{s.title}</h3>
        <Comm columns={s.columns} />
      </div>
    );
  }
  if (s.kind === "channels") {
    return (
      <div className="section full">
        <h3 className="section-title"><span className="section-num">{s.id}</span>{s.title}</h3>
        <Channels rows={s.rows} intro={s.intro} />
      </div>
    );
  }
  if (s.kind === "ideal") {
    return (
      <div className="section full">
        <Ideal steps={s.steps} closer={s.closer} />
      </div>
    );
  }
  // Default text section
  return (
    <div className="section">
      <h3 className="section-title"><span className="section-num">{s.id}</span>{s.title}</h3>
      {s.body && <p className="section-body">{s.body}</p>}
      {s.list && (
        <ul className="section-list">
          {s.list.map((x, i) => <li key={i}>{x}</li>)}
        </ul>
      )}
      {s.twoCol && (
        <div className="twocol">
          <div className="panel">
            <h5>{s.twoCol.left.title}</h5>
            <ul>{s.twoCol.left.items.map((x, i) => <li key={i}>{x}</li>)}</ul>
          </div>
          <div className="panel">
            <h5>{s.twoCol.right.title}</h5>
            <ul>{s.twoCol.right.items.map((x, i) => <li key={i}>{x}</li>)}</ul>
          </div>
        </div>
      )}
    </div>
  );
}

/* ---------- Chapter ---------- */
function Chapter({ ch }) {
  return (
    <section id={`ch-${ch.id}`} className="chapter" data-screen-label={`${ch.roman} ${ch.title}`}>
      <header className="chapter-header">
        <div className="chapter-roman">{ch.roman}</div>
        <div>
          <h2 className="chapter-title">{ch.title}</h2>
          <p className="chapter-lead">{ch.lead}</p>
        </div>
      </header>
      {ch.sections.map(s => <SectionRenderer s={s} key={s.id} />)}
    </section>
  );
}

/* ---------- TOC ---------- */
function TOC({ chapters, active, onJump, onSearch }) {
  return (
    <aside className="toc">
      <a className="toc-brand" href="#top" onClick={(e) => { e.preventDefault(); onJump("top"); }}>
        <img src="assets/mar-de-colas-logo.webp" alt="Mar de Colas — Clínica Veterinaria" />
      </a>
      <button className="toc-search" onClick={onSearch}>
        <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5">
          <circle cx="7" cy="7" r="5"></circle>
          <line x1="11" y1="11" x2="14" y2="14" strokeLinecap="round"></line>
        </svg>
        <span>Buscar en el protocolo</span>
        <kbd>⌘K</kbd>
      </button>
      <div className="toc-meta">Contenido</div>
      <ul className="toc-list">
        {chapters.map(c => (
          <li key={c.id}>
            <button
              className={classNames("toc-link", active === c.id && "active")}
              onClick={() => onJump(`ch-${c.id}`)}
            >
              <span className="roman">{c.roman}</span>
              <span className="label">{c.title}</span>
            </button>
          </li>
        ))}
      </ul>
    </aside>
  );
}

/* ---------- Search ---------- */
function buildIndex(chapters) {
  const out = [];
  chapters.forEach(ch => {
    out.push({ chId: ch.id, roman: ch.roman, chapter: ch.title, title: ch.title, snippet: ch.lead, anchor: `ch-${ch.id}` });
    ch.sections.forEach(s => {
      const collect = (text) => out.push({
        chId: ch.id, roman: ch.roman, chapter: ch.title,
        title: s.title || ch.title, snippet: text, anchor: `ch-${ch.id}`
      });
      if (s.body) collect(s.body);
      if (s.list) s.list.forEach(collect);
      if (s.rows) s.rows.forEach(r => collect([r.conducta, r.desc, r.ej, r.canal, r.estandar].filter(Boolean).join(" — ")));
      if (s.items) s.items.forEach(it => collect(`${it.title}. ${it.desc} Di: ${it.di}`));
      if (s.roles) s.roles.forEach(r => {
        collect(`${r.name}: ${r.mission}`);
        r.behaviors.forEach(b => collect(`${r.name} → ${b.title}: ${b.scripts.join(" / ")}`));
      });
      if (s.moments) s.moments.forEach(m => collect(`${m.name} — ${m.objective}. ${m.say.join(" / ")}`));
      if (s.situations) s.situations.forEach(sit => {
        sit.steps.forEach(st => collect(`${sit.name} → ${st.title}: ${st.lines.join(" / ")}`));
      });
      if (s.columns) {
        ["verbal", "noverbal", "evita"].forEach(k => s.columns[k]?.forEach(collect));
      }
      if (s.steps && Array.isArray(s.steps) && typeof s.steps[0] === "string") s.steps.forEach(collect);
      if (s.twoCol) {
        s.twoCol.left.items.forEach(collect);
        s.twoCol.right.items.forEach(collect);
      }
    });
  });
  return out;
}

function highlight(text, q) {
  if (!q) return text;
  const norm = (x) => x.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase();
  const idx = norm(text).indexOf(norm(q));
  if (idx === -1) return text;
  return (
    <>
      {text.slice(0, idx)}
      <mark>{text.slice(idx, idx + q.length)}</mark>
      {text.slice(idx + q.length)}
    </>
  );
}

function Search({ open, onClose, index, onJump }) {
  const [q, setQ] = useState("");
  const [sel, setSel] = useState(0);
  const inputRef = useRef(null);
  useEffect(() => { if (open) { setTimeout(() => inputRef.current?.focus(), 30); setQ(""); setSel(0); } }, [open]);

  const results = useMemo(() => {
    if (!q.trim()) return [];
    const norm = (x) => x.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase();
    const nq = norm(q);
    return index
      .map(it => ({ it, score: (norm(it.title).includes(nq) ? 2 : 0) + (norm(it.snippet).includes(nq) ? 1 : 0) }))
      .filter(x => x.score > 0)
      .slice(0, 30)
      .map(x => x.it);
  }, [q, index]);

  useEffect(() => {
    if (!open) return;
    const onKey = (e) => {
      if (e.key === "Escape") onClose();
      if (e.key === "ArrowDown") { e.preventDefault(); setSel(s => Math.min(results.length - 1, s + 1)); }
      if (e.key === "ArrowUp") { e.preventDefault(); setSel(s => Math.max(0, s - 1)); }
      if (e.key === "Enter" && results[sel]) {
        onJump(results[sel].anchor);
        onClose();
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open, results, sel, onClose, onJump]);

  if (!open) return null;
  return (
    <div className="search-overlay" onClick={onClose}>
      <div className="search-card" onClick={(e) => e.stopPropagation()}>
        <input
          ref={inputRef}
          className="search-input"
          placeholder="Buscar capítulos, frases, situaciones…"
          value={q}
          onChange={(e) => { setQ(e.target.value); setSel(0); }}
        />
        <div className="search-results">
          {q && results.length === 0 && <div className="search-empty">Sin resultados para «{q}»</div>}
          {results.map((r, i) => (
            <button
              key={i}
              className={classNames("search-result", i === sel && "active")}
              onMouseEnter={() => setSel(i)}
              onClick={() => { onJump(r.anchor); onClose(); }}
            >
              <div className="crumb">{r.roman} · {r.chapter}</div>
              <div className="title">{highlight(r.title, q)}</div>
              <div className="snippet">{highlight(r.snippet, q)}</div>
            </button>
          ))}
        </div>
        <div className="search-foot">
          <span><kbd>↑</kbd><kbd>↓</kbd> navegar · <kbd>↵</kbd> ir · <kbd>esc</kbd> cerrar</span>
          <span>{results.length} resultados</span>
        </div>
      </div>
    </div>
  );
}

/* ---------- App ---------- */
function App() {
  const data = window.PROTOCOL;
  const chapters = data.chapters;
  const [active, setActive] = useState(chapters[0].id);
  const [searchOpen, setSearchOpen] = useState(false);
  const [progress, setProgress] = useState(0);
  const index = useMemo(() => buildIndex(chapters), [chapters]);

  // Tweaks
  const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
    "theme": "light",
    "density": "comfortable",
    "primaryHue": 268,
    "primaryChroma": 0.13,
    "primaryLightness": 0.34
  }/*EDITMODE-END*/;
  const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS);

  // Apply theme + density to root
  useEffect(() => {
    document.documentElement.setAttribute("data-theme", tweaks.theme);
    document.documentElement.setAttribute("data-density", tweaks.density);
    const root = document.documentElement.style;
    const L = tweaks.primaryLightness, C = tweaks.primaryChroma, H = tweaks.primaryHue;
    root.setProperty("--primary", `oklch(${L} ${C} ${H})`);
    root.setProperty("--primary-soft", tweaks.theme === "dark"
      ? `oklch(0.28 ${Math.min(0.06, C)} ${H})`
      : `oklch(0.94 ${Math.min(0.03, C * 0.5)} ${H})`);
    root.setProperty("--primary-ink", tweaks.theme === "dark"
      ? `oklch(0.85 ${Math.min(0.08, C)} ${H})`
      : `oklch(${Math.max(0.28, L - 0.1)} ${Math.min(0.09, C + 0.01)} ${H})`);
  }, [tweaks]);

  // Scroll-spy + progress
  useEffect(() => {
    const obs = new IntersectionObserver((entries) => {
      const visible = entries.filter(e => e.isIntersecting)
        .sort((a, b) => b.intersectionRatio - a.intersectionRatio);
      if (visible[0]) {
        const id = visible[0].target.id.replace("ch-", "");
        setActive(id);
      }
    }, { rootMargin: "-30% 0px -55% 0px", threshold: [0, 0.25, 0.5, 1] });
    chapters.forEach(c => {
      const el = document.getElementById(`ch-${c.id}`);
      if (el) obs.observe(el);
    });
    const onScroll = () => {
      const h = document.documentElement;
      const total = h.scrollHeight - h.clientHeight;
      setProgress(total > 0 ? Math.min(100, Math.max(0, (h.scrollTop / total) * 100)) : 0);
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => { obs.disconnect(); window.removeEventListener("scroll", onScroll); };
  }, [chapters]);

  const jump = useCallback((anchor) => {
    if (anchor === "top") { window.scrollTo({ top: 0, behavior: "smooth" }); return; }
    const el = document.getElementById(anchor);
    if (el) {
      const y = el.getBoundingClientRect().top + window.scrollY - 12;
      window.scrollTo({ top: y, behavior: "smooth" });
    }
  }, []);

  // Cmd-K
  useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault(); setSearchOpen(v => !v);
      } else if (e.key === "/" && !["INPUT", "TEXTAREA"].includes(document.activeElement?.tagName)) {
        e.preventDefault(); setSearchOpen(true);
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  const {
    TweaksPanel, TweakSection, TweakRadio, TweakSlider
  } = window;

  return (
    <>
      <div className="progress"><div className="progress-fill" style={{ width: `${progress}%` }}></div></div>

      <header className="topbar">
        <img className="topbar-mark" src="assets/mar-de-colas-logo.webp" alt="Mar de Colas" />
        <span className="topbar-spacer"></span>
        <button className="topbar-btn" onClick={() => setSearchOpen(true)}>Buscar</button>
      </header>

      <div className="shell" id="top">
        <TOC chapters={chapters} active={active} onJump={jump} onSearch={() => setSearchOpen(true)} />
        <main className="reading">
          <section className="cover">
            <div className="cover-eyebrow">
              <span>{data.meta.brand}</span>
              <span className="dot">●</span>
              <span>{data.meta.kind}</span>
              <span className="dot">●</span>
              <span>{data.meta.version}</span>
            </div>
            <h1 className="cover-title">Protocolo de <em>Atención al Cliente</em></h1>
            <p className="cover-sub">{data.meta.promise}</p>
                      </section>

          {chapters.map(ch => <Chapter ch={ch} key={ch.id} />)}

          <footer className="colophon">
            <span>Mar de Colas · Documento Interno · v1.0</span>
            <span>Manual digital interactivo</span>
          </footer>
        </main>
      </div>

      <Search open={searchOpen} onClose={() => setSearchOpen(false)} index={index} onJump={jump} />

      <TweaksPanel title="Tweaks · Manual">
        <TweakSection title="Apariencia">
          <TweakRadio
            label="Tema"
            value={tweaks.theme}
            onChange={(v) => setTweak("theme", v)}
            options={[{ value: "light", label: "Claro" }, { value: "dark", label: "Oscuro" }]}
          />
          <TweakRadio
            label="Densidad"
            value={tweaks.density}
            onChange={(v) => setTweak("density", v)}
            options={[{ value: "comfortable", label: "Cómodo" }, { value: "compact", label: "Compacto" }]}
          />
        </TweakSection>
        <TweakSection title="Color principal">
          <TweakSlider label="Tono" min={0} max={360} step={1}
            value={tweaks.primaryHue} onChange={(v) => setTweak("primaryHue", v)} />
          <TweakSlider label="Saturación" min={0} max={0.18} step={0.01}
            value={tweaks.primaryChroma} onChange={(v) => setTweak("primaryChroma", v)} />
          <TweakSlider label="Luminosidad" min={0.28} max={0.6} step={0.01}
            value={tweaks.primaryLightness} onChange={(v) => setTweak("primaryLightness", v)} />
          <div style={{
            height: 28, borderRadius: 6,
            background: `oklch(${tweaks.primaryLightness} ${tweaks.primaryChroma} ${tweaks.primaryHue})`
          }}></div>
        </TweakSection>
      </TweaksPanel>
    </>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
