const byId = (id) => document.getElementById(id);

function element(tag, className, text) {
  const node = document.createElement(tag);
  if (className) node.className = className;
  if (text !== undefined) node.textContent = String(text);
  return node;
}

function chip(text, tone = "") {
  return element("span", `chip ${tone}`.trim(), text);
}

function links(sources) {
  const list = element("div", "source-links");
  for (const [index, href] of sources.entries()) {
    const link = element("a", "", index ? `source ${index + 1}` : "primary source");
    link.href = href;
    if (/^https:/.test(href)) {
      link.target = "_blank";
      link.rel = "noopener noreferrer";
    }
    list.append(link);
  }
  return list;
}

function accessList(access) {
  const definition = element("dl", "access");
  for (const [name, value] of Object.entries(access)) {
    definition.append(element("dt", "", name.replaceAll("_", " ")), element("dd", "", value));
  }
  return definition;
}

function renderRelay(relay) {
  const card = element("article", "card relay-card");
  const heading = element("div", "card-heading");
  const title = element("h3", "", relay.name);
  const endpoint = element("code", "endpoint", relay.url);
  heading.append(title, endpoint);
  const roles = element("div", "chips");
  relay.roles.forEach((role) => roles.append(chip(role)));
  roles.append(chip(`read: ${relay.access.read}`, relay.access.read === "observed" ? "good" : "warn"));
  roles.append(chip(`write: ${relay.access.write}`, relay.access.write === "unverified" ? "warn" : ""));
  const evidence = element("p", "evidence", `${relay.observation.signed_events} signed events sampled · ${relay.observation.valid_root_manifests + relay.observation.valid_named_manifests} valid current manifests · ${relay.observation.repository_announcements} repository announcements · EOSE ${relay.observation.eose ? "received" : "missing"}`);
  card.append(heading, roles, element("p", "fit", relay.fit), accessList(relay.access), evidence, links(relay.sources));
  return card;
}

function renderProject(project) {
  const card = element("article", "card project-card");
  const eyebrow = element("p", "card-label", project.category);
  const title = element("h3", "", project.name);
  const surfaces = element("ul", "surface-list");
  project.agent_surfaces.forEach((surface) => surfaces.append(element("li", "", surface)));
  const tags = element("div", "chips");
  tags.append(chip(project.maturity));
  card.append(eyebrow, title, tags, surfaces, accessList(project.access), element("p", "warning", project.warning), links(project.sources));
  return card;
}

function renderWatch(item) {
  const row = element("article", "watch-row");
  const name = element("h3", "", item.name);
  row.append(name, element("code", "endpoint", item.url), chip(item.result, "bad"), element("p", "", item.note));
  return row;
}

function renderStep(step, index) {
  const card = element("article", "step-card");
  card.append(element("span", "step-number", String(index + 1).padStart(2, "0")), element("h3", "", step.name), element("p", "", step.description));
  const tags = element("div", "chips");
  tags.append(chip(step.actor), chip(step.gate, step.gate.includes("refuse") || step.gate.includes("wait") ? "warn" : "good"));
  card.append(tags);
  return card;
}

async function main() {
  const response = await fetch("./agent-resources.json", { cache: "no-store" });
  if (!response.ok) throw new Error(`resource HTTP ${response.status}`);
  const data = await response.json();
  data.workflow.steps.forEach((step, index) => byId("workflow").append(renderStep(step, index)));
  data.relays.forEach((relay) => byId("relays").append(renderRelay(relay)));
  data.retry_watch.forEach((item) => byId("retry-watch").append(renderWatch(item)));
  data.projects.forEach((project) => byId("projects").append(renderProject(project)));
  data.methodology.forEach((line) => byId("methodology").append(element("li", "", line)));
  byId("relay-summary").textContent = `${data.relays.length} bounded candidates; ${data.retry_watch.length} retry observations.`;
  byId("workflow-summary").textContent = data.workflow.summary;
  byId("workflow-command").textContent = data.workflow.runtime.command;
  const smoke = data.workflow.runtime.bitcoin_public_smoke;
  byId("workflow-smoke").textContent = `Time-bounded Bitcoin transport evidence: ${smoke.providers.join(" + ")} agreed on ${smoke.agreement.join(", ")} at tip ${smoke.tip_height} (${smoke.at}). This was not a funding event.`;
  byId("project-summary").textContent = `${data.projects.length} agent-facing projects and protocols.`;
  byId("updated").textContent = `Evidence snapshot: ${new Date(data.updated_at).toLocaleString(undefined, { dateStyle: "medium", timeStyle: "short", timeZone: "UTC" })} UTC.`;
  document.body.dataset.rendered = "true";
}

main().catch((error) => {
  const fatal = element("p", "fatal", `Resource could not render: ${error.message}. Use the machine-readable JSON link.`);
  byId("resource").prepend(fatal);
  document.body.dataset.rendered = "error";
});
