(() => {
  const roots = [...document.querySelectorAll("[data-word-companion-presence]")]
    .filter((node) => node.dataset.wordCompanionPresence !== "false");
  if (roots.length === 0 || !window.signalR) {
    return;
  }

  const labelFor = (status) => (status?.isConnected || status?.IsConnected ? "Connected" : status?.status || status?.Status || "Offline");
  const field = (status, camel, pascal) => status?.[camel] ?? status?.[pascal] ?? null;
  let companionConnected = false;
  let companionDocumentOpen = false;
  let currentScanStatus = document.querySelector("[data-onboarding-scan-panel]")?.dataset.scanStatus || "NotStarted";
  let scanStartedInThisPage = currentScanStatus === "Running";

  const formatTime = (value) => {
    if (!value) {
      return "No heartbeat yet";
    }

    const date = new Date(value);
    return Number.isNaN(date.getTime()) ? "No heartbeat yet" : `Last heartbeat ${date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}`;
  };

  const applyStatus = (status) => {
    const connected = !!field(status, "isConnected", "IsConnected");
    const documentOpen = !!field(status, "documentOpen", "DocumentOpen");
    const version = field(status, "companionVersion", "CompanionVersion") || "Waiting";
    const documentName = field(status, "currentDocumentName", "CurrentDocumentName") || "No document reported yet";
    const label = connected ? "Connected" : labelFor(status);
    companionConnected = connected;
    companionDocumentOpen = documentOpen;
    const title = [
      `Word Companion: ${label}`,
      version && version !== "Waiting" ? `Version ${version}` : "",
      documentName && documentName !== "No document reported yet" ? documentName : "",
      formatTime(field(status, "lastHeartbeatUtc", "LastHeartbeatUtc"))
    ].filter(Boolean).join("\n");

    for (const root of roots) {
      root.classList.toggle("is-connected", connected);
      root.classList.toggle("is-offline", !connected);
      root.dataset.wordCompanionStatus = label;
      root.title = title;
    }

    document.querySelectorAll("[data-word-companion-status-label]").forEach((node) => {
      node.textContent = label;
    });
    document.querySelectorAll("[data-word-companion-waiting-status]").forEach((node) => {
      node.textContent = connected ? "Word Companion Connected" : "Word Companion disconnected. Waiting for reconnection...";
    });
    document.querySelectorAll("[data-word-companion-connected-copy]").forEach((node) => {
      if (!connected) {
        node.textContent = "Open Word and start the Companion. This page will update automatically.";
      } else if (!documentOpen) {
        node.textContent = "Open your manuscript in Word, then the scan button will appear.";
      } else if (currentScanStatus === "Complete") {
        node.textContent = "Your scan is ready. Review what PlotDirector found before anything is imported.";
      } else if (currentScanStatus === "Running") {
        node.textContent = "The Companion is reading your manuscript and sending structure back to PlotDirector.";
      } else {
        node.textContent = "Your Companion is connected. Scan your manuscript when you are ready.";
      }
    });
    document.querySelectorAll("[data-word-companion-version]").forEach((node) => {
      node.textContent = version;
    });
    document.querySelectorAll("[data-word-companion-document]").forEach((node) => {
      node.textContent = documentName;
    });
    document.querySelectorAll("[data-word-companion-dashboard-title]").forEach((node) => {
      node.textContent = connected ? "Word Companion Connected" : "Connect your Word Companion";
    });
    document.querySelectorAll("[data-word-companion-dashboard-description]").forEach((node) => {
      node.textContent = connected
        ? "Your Word Companion is ready for this story setup."
        : "Open Word, start the Companion, and sign in with your PlotDirector account.";
    });
    updateScanButton();
  };

  const numberText = (value) => {
    const number = Number.parseInt(value || "0", 10);
    return Number.isInteger(number) ? number.toLocaleString() : "0";
  };

  const updateScanButton = () => {
    document.querySelectorAll("[data-onboarding-scan-start]").forEach((button) => {
      button.disabled = !companionConnected || !companionDocumentOpen || currentScanStatus === "Running";
      button.textContent = currentScanStatus === "Complete" ? "Scan again" : "Scan manuscript";
    });
  };

  const applyScanState = (state) => {
    if (!state) {
      return;
    }

    const status = field(state, "status", "Status") || "NotStarted";
    if (status === "Running") {
      scanStartedInThisPage = true;
    }
    currentScanStatus = status;
    const message = field(state, "message", "Message") || (status === "Complete" ? "Scan complete. Review what PlotDirector found." : "Ready to scan");
    const percent = field(state, "percentComplete", "PercentComplete");
    const previewId = field(state, "previewID", "PreviewID") || field(state, "previewId", "PreviewId");
    const panel = document.querySelector("[data-onboarding-scan-panel]");
    if (panel) {
      panel.dataset.scanStatus = status;
      panel.classList.toggle("is-running", status === "Running");
      panel.classList.toggle("is-complete", status === "Complete");
      panel.classList.toggle("is-failed", status === "Failed");
    }

    document.querySelectorAll("[data-onboarding-scan-message]").forEach((node) => {
      node.textContent = message;
    });
    document.querySelectorAll("[data-onboarding-scan-percent]").forEach((node) => {
      node.textContent = percent === null || percent === undefined ? "" : `${percent}%`;
    });
    document.querySelectorAll("[data-onboarding-scan-progress]").forEach((node) => {
      node.style.width = `${Math.max(0, Math.min(100, Number.parseInt(percent || "0", 10) || 0))}%`;
    });
    document.querySelectorAll("[data-onboarding-scan-chapters]").forEach((node) => {
      node.textContent = numberText(field(state, "chapterCount", "ChapterCount"));
    });
    document.querySelectorAll("[data-onboarding-scan-scenes]").forEach((node) => {
      node.textContent = numberText(field(state, "sceneCount", "SceneCount"));
    });
    document.querySelectorAll("[data-onboarding-scan-characters]").forEach((node) => {
      node.textContent = numberText(field(state, "characterCandidateCount", "CharacterCandidateCount"));
    });
    document.querySelectorAll("[data-onboarding-scan-words]").forEach((node) => {
      node.textContent = numberText(field(state, "totalWordCount", "TotalWordCount"));
    });
    document.querySelectorAll("[data-onboarding-scan-review]").forEach((node) => {
      const ready = status === "Complete" && previewId;
      node.classList.toggle("disabled", !ready);
      node.setAttribute("aria-disabled", String(!ready));
      node.href = ready ? `/onboarding/scan-review?previewId=${encodeURIComponent(previewId)}` : "#";
    });
    updateScanButton();
    if (status === "Complete"
      && previewId
      && document.querySelector("[data-onboarding-auto-review]")
      && scanStartedInThisPage
      && !document.body.dataset.onboardingReviewRedirected) {
      document.body.dataset.onboardingReviewRedirected = "true";
      window.location.href = `/onboarding/scan-review?previewId=${encodeURIComponent(previewId)}`;
    }
  };

  const connection = new signalR.HubConnectionBuilder()
    .withUrl("/hubs/word-companion-follow")
    .withAutomaticReconnect()
    .build();

  connection.on("WordCompanionPresenceChanged", applyStatus);
  connection.on("OnboardingScanStateChanged", applyScanState);
  connection.on("OnboardingScanProgress", applyScanState);
  connection.on("OnboardingScanCompleted", applyScanState);
  connection.on("OnboardingScanFailed", applyScanState);
  connection.on("OnboardingBuildProgress", (state) => {
    const message = field(state, "message", "Message") || "Preparing chapters...";
    const percent = field(state, "percentComplete", "PercentComplete");
    const safePercent = Math.max(0, Math.min(100, Number.parseInt(percent || "0", 10) || 0));
    document.querySelectorAll("[data-onboarding-build-panel]").forEach((node) => {
      node.classList.add("is-running");
    });
    document.querySelectorAll("[data-onboarding-build-message]").forEach((node) => {
      node.textContent = message;
    });
    document.querySelectorAll("[data-onboarding-build-percent]").forEach((node) => {
      node.textContent = percent === null || percent === undefined ? "" : `${percent}%`;
    });
    document.querySelectorAll("[data-onboarding-build-progress]").forEach((node) => {
      node.style.width = `${safePercent}%`;
    });
  });
  connection.on("OnboardingBuildCompleted", (result) => {
    const previewId = field(result, "previewID", "PreviewID") || field(result, "previewId", "PreviewId");
    if (previewId) {
      window.location.href = `/onboarding/build-complete?previewId=${encodeURIComponent(previewId)}`;
    }
  });
  connection.onreconnecting(() => applyStatus({ status: "Connecting", isConnected: false }));
  connection.onreconnected(() => connection.invoke("WatchCompanionPresence").then(applyStatus).catch(() => {}));
  connection.onclose(() => applyStatus({ status: "Offline", isConnected: false }));

  connection.start()
    .then(() => connection.invoke("WatchCompanionPresence"))
    .then(applyStatus)
    .catch(() => applyStatus({ status: "Offline", isConnected: false }));

  document.querySelectorAll("[data-onboarding-scan-start]").forEach((button) => {
    button.addEventListener("click", async () => {
      button.disabled = true;
      applyScanState({ status: "Running", message: "Asking the Word Companion to scan...", percentComplete: 0 });
      try {
        const state = await connection.invoke("StartOnboardingManuscriptScan");
        applyScanState(state);
      } catch (error) {
        applyScanState({
          status: "Failed",
          message: error?.message || "The scan could not start. Reconnect the Word Companion and try again."
        });
      }
    });
  });

  document.querySelectorAll("[data-onboarding-build-start]").forEach((button) => {
    button.addEventListener("click", async () => {
      const previewId = button.dataset.previewId;
      if (!previewId) {
        return;
      }
      button.disabled = true;
      document.querySelectorAll("[data-onboarding-build-panel]").forEach((node) => {
        node.classList.add("is-running");
      });
      document.querySelectorAll("[data-onboarding-build-message]").forEach((node) => {
        node.textContent = "Preparing the approved chapters...";
      });
      document.querySelectorAll("[data-onboarding-build-percent]").forEach((node) => {
        node.textContent = "0%";
      });
      document.querySelectorAll("[data-onboarding-build-progress]").forEach((node) => {
        node.style.width = "0%";
      });
      try {
        const result = await connection.invoke("StartOnboardingProjectBuild", previewId);
        const returnedPreviewId = field(result, "previewID", "PreviewID") || previewId;
        window.location.href = `/onboarding/build-complete?previewId=${encodeURIComponent(returnedPreviewId)}`;
      } catch (error) {
        button.disabled = false;
        document.querySelectorAll("[data-onboarding-build-panel]").forEach((node) => {
          node.classList.remove("is-running");
        });
        document.querySelectorAll("[data-onboarding-build-message]").forEach((node) => {
          node.textContent = error?.message || "The approved chapters could not be prepared. Check the review and try again.";
        });
        document.querySelectorAll("[data-onboarding-build-percent]").forEach((node) => {
          node.textContent = "";
        });
      }
    });
  });
})();
