/* eslint-disable */
// Shared header + footer used on every page (landing + 4 sections).

window.GSC_NAV = [
  { href: "index.html",                slug: "home",     label: "Home" },
  { href: "introduction.html",         slug: "01",       label: "01 Introduction" },
  { href: "community-context.html",    slug: "02",       label: "02 Context" },
  { href: "strategic-priorities.html", slug: "03",       label: "03 Priorities" },
  { href: "implementation.html",       slug: "04",       label: "04 Implementation" },
  { href: "index.html#roadmap",        slug: "roadmap",  label: "Roadmap" },
  { href: "strategy.html",             slug: "pdf",      label: "PDF" }
];

function Header({ activeSlug }) {
  return (
    <header className="site-header">
      <div className="shell site-header__row">
        <a href="index.html" className="site-header__logo">
          <span className="site-header__logo-mark">
            <img src="../../assets/logo-gsc-colour.png" alt="Gilgandra Shire Council" />
          </span>
          <span className="site-header__title">
            Aged Care &amp; Disability Strategy
            <small>2026 — 2030 · Draft</small>
          </span>
        </a>
        <nav className="site-nav">
          {window.GSC_NAV.map(item => (
            <a
              key={item.slug}
              href={item.href}
              aria-current={item.slug === activeSlug ? "page" : undefined}
              className={item.slug === "home" ? "home-link" : ""}
            >
              {item.label}
            </a>
          ))}
        </nav>
      </div>
    </header>
  );
}

function Footer() {
  return (
    <footer className="site-footer">
      <div className="shell">
        <div className="site-footer__row">
          <div className="site-footer__mark">
            <img src="../../assets/mark-live-enjoy-grow.png" alt="Live · Enjoy · Grow" />
            <div style={{ marginTop: 16, color: "rgba(255,255,255,0.6)", fontSize: 13, letterSpacing: "0.06em" }}>
              {window.GSC_URL}
            </div>
          </div>
          <div>
            <h4>The Strategy</h4>
            <a href="introduction.html">01 Introduction</a>
            <a href="community-context.html">02 Community &amp; Service Context</a>
            <a href="strategic-priorities.html">03 Strategic Priorities &amp; Actions</a>
            <a href="implementation.html">04 Implementation &amp; Governance</a>
            <a href="index.html#roadmap">Interactive roadmap</a>
            <a href="strategy.html">Read the PDF</a>
          </div>
          <div>
            <h4>Get in touch</h4>
            <a href="#">Aged Care &amp; Disability Directorate</a>
            <a href="#">Gilgandra Shire Council</a>
            <a href="#">15 Warren Road, Gilgandra NSW 2827</a>
            <a href="#">(02) 6817 8800</a>
            <a href="#">council@gilgandra.nsw.gov.au</a>
          </div>
        </div>
        <div className="site-footer__bottom">
          <span>© 2026 Gilgandra Shire Council. Draft Strategy v3.</span>
          <span>We acknowledge the Wiradjuri, Gamilaroi and Wailwan nations.</span>
        </div>
      </div>
    </footer>
  );
}

// ---------------------------------------------------------------------------
// Listen / Stop button — wraps the browser's built-in speechSynthesis so
// every section of the site can be read aloud. No API key, no external
// service, no network call. Falls back silently if a browser doesn't
// support the Web Speech API.
// ---------------------------------------------------------------------------
function SpeakButton({ getText, label }) {
  const supported = typeof window !== "undefined" && "speechSynthesis" in window;
  const [speaking, setSpeaking] = React.useState(false);

  React.useEffect(() => {
    if (!supported) return;
    // If another SpeakButton starts speaking, the synthesis cancel will fire
    // an 'end' event on us — keep our local state in sync.
    return () => { window.speechSynthesis && window.speechSynthesis.cancel(); };
  }, [supported]);

  if (!supported) return null;

  const pickVoice = () => {
    const voices = window.speechSynthesis.getVoices() || [];
    // Prefer an Australian English voice, then any en-* voice, then default.
    return voices.find(v => /en[-_]AU/i.test(v.lang))
        || voices.find(v => /en[-_]GB/i.test(v.lang))
        || voices.find(v => /^en/i.test(v.lang))
        || null;
  };

  const toggle = () => {
    const synth = window.speechSynthesis;
    if (speaking) { synth.cancel(); setSpeaking(false); return; }
    // Cancel anything else currently being read.
    synth.cancel();
    const raw = typeof getText === "function" ? getText() : String(getText || "");
    const text = (raw || "").replace(/\s+/g, " ").trim();
    if (!text) return;
    const u = new SpeechSynthesisUtterance(text);
    const voice = pickVoice();
    if (voice) u.voice = voice;
    u.rate = 1.0;
    u.pitch = 1.0;
    u.onend = () => setSpeaking(false);
    u.onerror = () => setSpeaking(false);
    setSpeaking(true);
    synth.speak(u);
  };

  return (
    <button
      type="button"
      className={`speak-btn ${speaking ? "is-speaking" : ""}`}
      onClick={toggle}
      aria-label={speaking ? "Stop reading aloud" : (label || "Listen to this section")}
      aria-pressed={speaking}
      title={speaking ? "Stop" : "Listen"}
    >
      <svg className="speak-btn__icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
        {speaking ? (
          <React.Fragment>
            <rect x="6" y="5" width="4" height="14" rx="1" />
            <rect x="14" y="5" width="4" height="14" rx="1" />
          </React.Fragment>
        ) : (
          <React.Fragment>
            <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" />
            <path d="M15.54 8.46a5 5 0 0 1 0 7.07" />
            <path d="M19.07 4.93a10 10 0 0 1 0 14.14" />
          </React.Fragment>
        )}
      </svg>
      <span className="speak-btn__label">{speaking ? "Stop" : "Listen"}</span>
    </button>
  );
}

// ---------------------------------------------------------------------------
// blockToText / gatherSectionText — helpers used by section-page.jsx to
// turn a slice of the `blocks` array into a single readable string. Each
// block kind is mapped to its natural spoken form.
// ---------------------------------------------------------------------------
function blockToText(b) {
  if (!b) return "";
  switch (b.kind) {
    case "h2": case "h3": case "h4": case "subhead": case "caption":
    case "lede": case "p": case "vision": case "implication":
      return b.text || "";
    case "byline":    return `${b.name}, ${b.role}.`;
    case "signature": return "";
    case "ul":        return (b.items || []).join(". ");
    case "planGrid":  return (b.items || []).map(it => `${it.name}. ${it.note}`).join(". ");
    case "serviceGrid": return (b.items || []).map(it => typeof it === "string" ? it : it.name).join(", ");
    case "statGroup": {
      const parts = [];
      if (b.title)   parts.push(b.title);
      if (b.service) parts.push(b.service);
      (b.tiles || []).forEach(t => {
        const sub = t.subList ? `, including ${t.subList.join(", ")}` : "";
        parts.push(`${t.value} ${t.label}${sub}`);
      });
      if (b.narratives) parts.push((b.narratives || []).join(". "));
      if (b.implication) parts.push(`Strategic implication: ${b.implication}`);
      if (b.footnote)    parts.push(b.footnote);
      return parts.join(". ");
    }
    case "consultGrid": return (b.items || []).map(it => `${it.count} ${it.title}. ${it.note}`).join(". ");
    case "personGrid":  return (b.items || []).map(it => it.label).join(", ");
    case "participantProfile": return (b.lines || []).join(". ");
    case "boxedNote":  return `${b.title}. ${b.body}`;
    case "quote":      return `Quote: "${b.body}" — ${b.cite}.`;
    case "roleGrid":   return (b.items || []).map(it => `${it.name}. ${it.sub}. ${it.body}`).join(". ");
    case "deliveryPillars": return (b.items || []).join(", ");
    case "references": return ""; // skip — long and not useful spoken
    case "photo": case "diagram": case "deliveryDiagram": case "deliveryFlow":
      return b.caption || "";
    default: return b.text || "";
  }
}

function gatherSectionText(blocks, startIdx) {
  // Read blocks from `startIdx` (the h2) up to but not including the next h2.
  const parts = [];
  for (let i = startIdx; i < blocks.length; i++) {
    const b = blocks[i];
    if (i > startIdx && b.kind === "h2") break;
    const t = blockToText(b);
    if (t) parts.push(t);
  }
  return parts.join(". ");
}

// ---------------------------------------------------------------------------
// buildStrategyBriefing — concatenate the entire strategy (all four chapters
// + every priority + every action) into one long grounding briefing the
// AI worker can pass to Claude as a cacheable system message. Memoized
// because the underlying data never changes during a page's lifetime.
// ---------------------------------------------------------------------------
let _strategyBriefingCache = null;
function buildStrategyBriefing() {
  if (_strategyBriefingCache) return _strategyBriefingCache;
  const s01 = window.GSC_SECTION_01;
  const s02 = window.GSC_SECTION_02;
  const s04 = window.GSC_SECTION_04;
  const direction = window.GSC_DIRECTION;
  const priorities = window.GSC_PRIORITIES || [];
  const roadmap = window.GSC_ROADMAP;

  const sectionBlocksToText = (section) =>
    (section && section.blocks ? section.blocks : [])
      .map(b => blockToText(b))
      .filter(Boolean)
      .join("\n\n");

  const prioritiesText = priorities.map(p => {
    const intro = (p.intro || []).join("\n\n");
    const alignment = (p.alignment || [])
      .map(a => `${a.framework}: ${a.lines.join(" · ")}`)
      .join("; ");
    const actions = (p.actionGroups || []).map(g => {
      const tasks = (g.tasks || [])
        .map(t => `    • ${t.task}  [time: ${t.time}, cost: ${t.cost}]`)
        .join("\n");
      const funding = (g.funding && g.funding.length)
        ? `\n    Funding pathway: ${g.funding.join("; ")}`
        : "";
      return `  Action: ${g.action}\n${tasks}${funding}`;
    }).join("\n\n");
    return [
      `## Priority ${p.id}: ${p.title}`,
      `Tagline: ${p.sub}`,
      `CSP Outcome: ${p.cspOutcome}`,
      alignment ? `Alignment: ${alignment}` : "",
      `\nIntroduction:\n${intro}`,
      `\nActions and tasks:\n${actions}`,
    ].filter(Boolean).join("\n");
  }).join("\n\n---\n\n");

  const roadmapText = roadmap ? [
    "Year-by-year roadmap:",
    ...(roadmap.years || []).map(y => `- ${y.year} (${y.title}): ${y.blurb}`),
    "Ongoing across all years:",
    ...(roadmap.ongoing || []).map(o => `- ${o}`),
  ].join("\n") : "";

  const directionText = direction ? [
    "Strategic direction:",
    direction.intro,
    direction.body,
    `Aged care — ${direction.agedCare.title}: ${direction.agedCare.sub}. ${direction.agedCare.body}`,
    `Disability — ${direction.disability.title}: ${direction.disability.sub}. ${direction.disability.body}`,
    `Across both — ${direction.acrossBoth.title}: ${direction.acrossBoth.sub}. ${direction.acrossBoth.body}`,
    direction.prioritiesIntro,
  ].join("\n\n") : "";

  _strategyBriefingCache = [
    "# GILGANDRA AGED CARE & DISABILITY STRATEGY 2026–2030",
    "Below is the full strategy you must answer questions from. Quote it where helpful, paraphrase otherwise. Do not invent facts that aren't here.",
    "",
    "# SECTION 01 — INTRODUCTION",
    sectionBlocksToText(s01),
    "",
    "# SECTION 02 — COMMUNITY AND SERVICE CONTEXT",
    sectionBlocksToText(s02),
    "",
    "# SECTION 03 — STRATEGIC PRIORITIES AND ACTIONS",
    directionText,
    "",
    prioritiesText,
    "",
    "# ROADMAP",
    roadmapText,
    "",
    "# SECTION 04 — IMPLEMENTATION AND GOVERNANCE",
    sectionBlocksToText(s04),
  ].join("\n");
  return _strategyBriefingCache;
}

// System prompt that wraps the briefing — tone, scope, fallback behaviour.
function buildSystemPrompt() {
  return [
    "You are an assistant for Gilgandra Shire Council's Aged Care and Disability Strategy 2026–2030.",
    "Answer ONLY from the strategy briefing below.",
    "Write in a warm, plainspoken Australian council voice — first-person plural (we, our, us).",
    "Answer with enough detail to be genuinely useful — typically 1–3 short paragraphs. Use bullet points when the answer is naturally a list (e.g. listing actions, services, or stakeholder groups). Don't pad, but don't truncate either: finish your thought.",
    "Name places and services specifically (Cooee Lodge, Jack Towney Hostel, Orana Living, Carlginda Enterprises, Support at Home, Life Skills Centre, Care Connect, etc.) when they're relevant.",
    "If the question isn't covered by the briefing, say so honestly and suggest which chapter to read (01 Introduction, 02 Community & Service Context, 03 Strategic Priorities & Actions, or 04 Implementation & Governance).",
    "No emoji. Australian English spelling (organisation, programme, centre).",
    "",
    buildStrategyBriefing(),
  ].join("\n");
}

Object.assign(window, {
  Header, Footer, SpeakButton, blockToText, gatherSectionText,
  buildStrategyBriefing, buildSystemPrompt,
});
