diff --git a/PlotLine/Controllers/WordCompanionController.cs b/PlotLine/Controllers/WordCompanionController.cs index 66edf26..fd36c4e 100644 --- a/PlotLine/Controllers/WordCompanionController.cs +++ b/PlotLine/Controllers/WordCompanionController.cs @@ -156,6 +156,20 @@ public sealed class WordCompanionController( return response is null ? BadRequest() : Ok(response); } + [HttpGet("runtime/assets")] + public async Task GetRuntimeAssets([FromQuery] int projectId, [FromQuery] Guid documentGuid) + { + var response = await wordCompanion.ListRuntimeAssetAliasesAsync(projectId, documentGuid); + return response is null ? BadRequest() : Ok(response); + } + + [HttpPost("runtime/asset-suggestions")] + public async Task CreateRuntimeAssetSuggestions(WordCompanionRuntimeAssetSuggestionsRequest request) + { + var response = await wordCompanion.CreateRuntimeAssetSuggestionsAsync(request); + return response is null ? BadRequest() : Ok(response); + } + [HttpGet("manuscript/book/{bookId:int}")] public async Task GetManuscriptForBook(int bookId) { diff --git a/PlotLine/Data/WordCompanionRepository.cs b/PlotLine/Data/WordCompanionRepository.cs index d74023a..bc572f7 100644 --- a/PlotLine/Data/WordCompanionRepository.cs +++ b/PlotLine/Data/WordCompanionRepository.cs @@ -23,6 +23,8 @@ public interface IWordCompanionRepository Task ValidateRuntimeCurrentSceneAsync(int userId, WordCompanionRuntimeCurrentSceneRequest request); Task> ListRuntimeCharacterAliasesAsync(int userId, int projectId, Guid documentGuid); Task CreateRuntimeCharacterSuggestionsAsync(int userId, WordCompanionRuntimeCharacterSuggestionsRequest request); + Task> ListRuntimeAssetAliasesAsync(int userId, int projectId, Guid documentGuid); + Task CreateRuntimeAssetSuggestionsAsync(int userId, WordCompanionRuntimeAssetSuggestionsRequest request); Task AnalyseManuscriptAsync(int userId, WordCompanionManuscriptAnalyseRequest request); Task ImportManuscriptAsync(int userId, WordCompanionManuscriptImportRequest request); Task HasProjectAccessAsync(int projectId, int userId); @@ -298,6 +300,31 @@ public sealed class WordCompanionRepository(ISqlConnectionFactory connectionFact commandType: CommandType.StoredProcedure); } + public async Task> ListRuntimeAssetAliasesAsync(int userId, int projectId, Guid documentGuid) + { + using var connection = connectionFactory.CreateConnection(); + var rows = await connection.QueryAsync( + "dbo.WordCompanion_Runtime_AssetAlias_List", + new { UserID = userId, ProjectID = projectId, DocumentGuid = documentGuid }, + commandType: CommandType.StoredProcedure); + return rows.ToList(); + } + + public async Task CreateRuntimeAssetSuggestionsAsync(int userId, WordCompanionRuntimeAssetSuggestionsRequest request) + { + using var connection = connectionFactory.CreateConnection(); + return await connection.QuerySingleOrDefaultAsync( + "dbo.WordCompanion_Runtime_AssetSuggestions_Create", + new + { + UserID = userId, + request.DocumentGuid, + request.SceneId, + AssetIds = ToCsv(request.AssetIds) + }, + commandType: CommandType.StoredProcedure); + } + public async Task AnalyseManuscriptAsync(int userId, WordCompanionManuscriptAnalyseRequest request) { using var connection = connectionFactory.CreateConnection(); diff --git a/PlotLine/Models/WordCompanionApiModels.cs b/PlotLine/Models/WordCompanionApiModels.cs index 0fb4636..d8406aa 100644 --- a/PlotLine/Models/WordCompanionApiModels.cs +++ b/PlotLine/Models/WordCompanionApiModels.cs @@ -275,6 +275,35 @@ public sealed class WordCompanionRuntimeCharacterSuggestionsResponse public string Message { get; init; } = "No new character suggestions."; } +public sealed class WordCompanionRuntimeAssetAliasDto +{ + public int AssetId { get; init; } + public string Name { get; init; } = string.Empty; + public string MatchText { get; init; } = string.Empty; + public bool IsDisplayName { get; init; } +} + +public sealed class WordCompanionRuntimeAssetAliasResponse +{ + public int ProjectId { get; init; } + public IReadOnlyList Assets { get; init; } = []; +} + +public sealed class WordCompanionRuntimeAssetSuggestionsRequest +{ + public Guid DocumentGuid { get; set; } + public int SceneId { get; set; } + public IReadOnlyList AssetIds { get; set; } = []; +} + +public sealed class WordCompanionRuntimeAssetSuggestionsResponse +{ + public int SceneId { get; init; } + public int CreatedCount { get; init; } + public int SkippedCount { get; init; } + public string Message { get; init; } = "No new asset suggestions."; +} + public sealed class WordCompanionManuscriptDocumentDto { public int ManuscriptDocumentId { get; init; } diff --git a/PlotLine/Services/WordCompanionService.cs b/PlotLine/Services/WordCompanionService.cs index e488d43..dac898b 100644 --- a/PlotLine/Services/WordCompanionService.cs +++ b/PlotLine/Services/WordCompanionService.cs @@ -23,6 +23,8 @@ public interface IWordCompanionService Task ValidateRuntimeCurrentSceneAsync(WordCompanionRuntimeCurrentSceneRequest request); Task ListRuntimeCharacterAliasesAsync(int projectId, Guid documentGuid); Task CreateRuntimeCharacterSuggestionsAsync(WordCompanionRuntimeCharacterSuggestionsRequest request); + Task ListRuntimeAssetAliasesAsync(int projectId, Guid documentGuid); + Task CreateRuntimeAssetSuggestionsAsync(WordCompanionRuntimeAssetSuggestionsRequest request); Task GetRuntimeBookAsync(int bookId, Guid documentGuid); Task GetManuscriptForBookAsync(int bookId); Task LinkManuscriptAsync(WordCompanionManuscriptLinkRequest request); @@ -278,6 +280,36 @@ public sealed class WordCompanionService( : repository.CreateRuntimeCharacterSuggestionsAsync(RequireUserId(), request); } + public async Task ListRuntimeAssetAliasesAsync(int projectId, Guid documentGuid) + { + if (projectId <= 0 || documentGuid == Guid.Empty) + { + return null; + } + + var aliases = await repository.ListRuntimeAssetAliasesAsync(RequireUserId(), projectId, documentGuid); + return new WordCompanionRuntimeAssetAliasResponse + { + ProjectId = projectId, + Assets = aliases + }; + } + + public Task CreateRuntimeAssetSuggestionsAsync(WordCompanionRuntimeAssetSuggestionsRequest request) + { + request.AssetIds = request.AssetIds + .Where(id => id > 0) + .Distinct() + .Take(CharacterDiscoverySuggestionLimit) + .ToList(); + + return request.DocumentGuid == Guid.Empty + || request.SceneId <= 0 + || request.AssetIds.Count == 0 + ? Task.FromResult(null) + : repository.CreateRuntimeAssetSuggestionsAsync(RequireUserId(), request); + } + public async Task GetRuntimeBookAsync(int bookId, Guid documentGuid) { if (bookId <= 0 || documentGuid == Guid.Empty) diff --git a/PlotLine/Sql/103_Phase16K_WordCompanionAssetSuggestions.sql b/PlotLine/Sql/103_Phase16K_WordCompanionAssetSuggestions.sql new file mode 100644 index 0000000..e48c3f8 --- /dev/null +++ b/PlotLine/Sql/103_Phase16K_WordCompanionAssetSuggestions.sql @@ -0,0 +1,189 @@ +IF OBJECT_ID(N'dbo.SceneAssetSuggestions', N'U') IS NULL +BEGIN + CREATE TABLE dbo.SceneAssetSuggestions + ( + SceneAssetSuggestionID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_SceneAssetSuggestions PRIMARY KEY, + SceneID int NOT NULL, + AssetID int NOT NULL, + SuggestionSource nvarchar(50) NOT NULL CONSTRAINT DF_SceneAssetSuggestions_Source DEFAULT (N'Word Companion'), + DetectedUtc datetime2 NOT NULL CONSTRAINT DF_SceneAssetSuggestions_DetectedUtc DEFAULT SYSUTCDATETIME(), + Status nvarchar(20) NOT NULL CONSTRAINT DF_SceneAssetSuggestions_Status DEFAULT (N'Pending'), + Confidence nvarchar(20) NOT NULL CONSTRAINT DF_SceneAssetSuggestions_Confidence DEFAULT (N'High'), + Reason nvarchar(200) NULL, + CreatedByUserID int NOT NULL, + ReviewedByUserID int NULL, + ReviewedUtc datetime2 NULL, + CONSTRAINT FK_SceneAssetSuggestions_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID), + CONSTRAINT FK_SceneAssetSuggestions_StoryAssets FOREIGN KEY (AssetID) REFERENCES dbo.StoryAssets(StoryAssetID), + CONSTRAINT FK_SceneAssetSuggestions_CreatedByUser FOREIGN KEY (CreatedByUserID) REFERENCES dbo.AppUser(UserID), + CONSTRAINT FK_SceneAssetSuggestions_ReviewedByUser FOREIGN KEY (ReviewedByUserID) REFERENCES dbo.AppUser(UserID), + CONSTRAINT CK_SceneAssetSuggestions_Status CHECK (Status IN (N'Pending', N'Accepted', N'Rejected', N'Dismissed')), + CONSTRAINT CK_SceneAssetSuggestions_Confidence CHECK (Confidence IN (N'High', N'Medium', N'Low')) + ); +END; +GO + +IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_SceneAssetSuggestions_Pending' AND object_id = OBJECT_ID(N'dbo.SceneAssetSuggestions')) + CREATE UNIQUE INDEX UX_SceneAssetSuggestions_Pending ON dbo.SceneAssetSuggestions(SceneID, AssetID) WHERE Status = N'Pending'; +GO + +IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_SceneAssetSuggestions_SceneStatus' AND object_id = OBJECT_ID(N'dbo.SceneAssetSuggestions')) + CREATE INDEX IX_SceneAssetSuggestions_SceneStatus ON dbo.SceneAssetSuggestions(SceneID, Status, AssetID); +GO + +CREATE OR ALTER PROCEDURE dbo.WordCompanion_Runtime_AssetAlias_List + @UserID int, + @ProjectID int, + @DocumentGuid uniqueidentifier +AS +BEGIN + SET NOCOUNT ON; + + IF @DocumentGuid IS NULL + OR @DocumentGuid = '00000000-0000-0000-0000-000000000000' + OR @ProjectID <= 0 + RETURN; + + IF NOT EXISTS + ( + SELECT 1 + FROM dbo.ManuscriptDocuments md + INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = md.ProjectID + INNER JOIN dbo.Projects p ON p.ProjectID = md.ProjectID + WHERE md.DocumentGuid = @DocumentGuid + AND md.ProjectID = @ProjectID + AND md.IsActive = 1 + AND p.IsArchived = 0 + AND pua.UserID = @UserID + AND pua.IsActive = 1 + ) + RETURN; + + SELECT sa.StoryAssetID AS AssetId, + sa.AssetName AS Name, + sa.AssetName AS MatchText, + CAST(1 AS bit) AS IsDisplayName + FROM dbo.StoryAssets sa + WHERE sa.ProjectID = @ProjectID + AND sa.IsArchived = 0 + AND NULLIF(LTRIM(RTRIM(sa.AssetName)), N'') IS NOT NULL + + UNION ALL + + SELECT sa.StoryAssetID AS AssetId, + sa.AssetName AS Name, + aa.Alias AS MatchText, + CAST(0 AS bit) AS IsDisplayName + FROM dbo.StoryAssets sa + INNER JOIN dbo.AssetAliases aa ON aa.StoryAssetID = sa.StoryAssetID + WHERE sa.ProjectID = @ProjectID + AND sa.IsArchived = 0 + AND NULLIF(LTRIM(RTRIM(aa.Alias)), N'') IS NOT NULL + ORDER BY Name, AssetId, IsDisplayName DESC, MatchText; +END; +GO + +CREATE OR ALTER PROCEDURE dbo.WordCompanion_Runtime_AssetSuggestions_Create + @UserID int, + @DocumentGuid uniqueidentifier, + @SceneID int, + @AssetIds nvarchar(max) +AS +BEGIN + SET NOCOUNT ON; + + IF @DocumentGuid IS NULL + OR @DocumentGuid = '00000000-0000-0000-0000-000000000000' + OR @SceneID <= 0 + RETURN; + + DECLARE @ProjectID int; + DECLARE @ManuscriptDocumentID int; + + SELECT @ProjectID = b.ProjectID, + @ManuscriptDocumentID = md.ManuscriptDocumentID + FROM dbo.Scenes s + INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID + INNER JOIN dbo.Books b ON b.BookID = c.BookID + INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID + INNER JOIN dbo.ManuscriptDocuments md ON md.BookID = b.BookID + INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = b.ProjectID + WHERE s.SceneID = @SceneID + AND s.IsArchived = 0 + AND c.IsArchived = 0 + AND b.IsArchived = 0 + AND p.IsArchived = 0 + AND md.DocumentGuid = @DocumentGuid + AND md.IsActive = 1 + AND s.IsLinkedToManuscript = 1 + AND s.ManuscriptDocumentID = md.ManuscriptDocumentID + AND pua.UserID = @UserID + AND pua.IsActive = 1; + + IF @ProjectID IS NULL + RETURN; + + DECLARE @Requested table (AssetID int NOT NULL PRIMARY KEY); + + INSERT @Requested (AssetID) + SELECT DISTINCT TRY_CONVERT(int, LTRIM(RTRIM(value))) + FROM STRING_SPLIT(COALESCE(@AssetIds, N''), N',') + WHERE TRY_CONVERT(int, LTRIM(RTRIM(value))) IS NOT NULL + AND TRY_CONVERT(int, LTRIM(RTRIM(value))) > 0; + + IF NOT EXISTS (SELECT 1 FROM @Requested) + BEGIN + SELECT @SceneID AS SceneId, + 0 AS CreatedCount, + 0 AS SkippedCount, + N'No asset suggestions detected.' AS Message; + RETURN; + END; + + IF EXISTS + ( + SELECT 1 + FROM @Requested requested + WHERE NOT EXISTS + ( + SELECT 1 + FROM dbo.StoryAssets sa + WHERE sa.StoryAssetID = requested.AssetID + AND sa.ProjectID = @ProjectID + AND sa.IsArchived = 0 + ) + ) + RETURN; + + DECLARE @Inserted table (AssetID int NOT NULL PRIMARY KEY); + + INSERT dbo.SceneAssetSuggestions + (SceneID, AssetID, SuggestionSource, Status, Confidence, Reason, CreatedByUserID) + OUTPUT inserted.AssetID INTO @Inserted + SELECT @SceneID, + requested.AssetID, + N'Word Companion', + N'Pending', + N'High', + N'Detected in manuscript text', + @UserID + FROM @Requested requested + WHERE NOT EXISTS + (SELECT 1 FROM dbo.AssetEvents ae WHERE ae.SceneID = @SceneID AND ae.StoryAssetID = requested.AssetID) + AND NOT EXISTS + (SELECT 1 FROM dbo.SceneAssetLocations sal WHERE sal.SceneID = @SceneID AND sal.StoryAssetID = requested.AssetID) + AND NOT EXISTS + (SELECT 1 FROM dbo.AssetCustodyEvents ace WHERE ace.SceneID = @SceneID AND ace.StoryAssetID = requested.AssetID) + AND NOT EXISTS + (SELECT 1 FROM dbo.SceneAssetSuggestions suggestion WHERE suggestion.SceneID = @SceneID AND suggestion.AssetID = requested.AssetID); + + SELECT @SceneID AS SceneId, + (SELECT COUNT(*) FROM @Inserted) AS CreatedCount, + (SELECT COUNT(*) FROM @Requested) - (SELECT COUNT(*) FROM @Inserted) AS SkippedCount, + CASE + WHEN (SELECT COUNT(*) FROM @Inserted) = 1 THEN N'1 asset suggestion detected.' + WHEN (SELECT COUNT(*) FROM @Inserted) > 1 THEN CONCAT((SELECT COUNT(*) FROM @Inserted), N' asset suggestions detected.') + ELSE N'No new asset suggestions.' + END AS Message; +END; +GO diff --git a/PlotLine/wwwroot/js/word-companion-host.js b/PlotLine/wwwroot/js/word-companion-host.js index 7176cbb..399bf8e 100644 --- a/PlotLine/wwwroot/js/word-companion-host.js +++ b/PlotLine/wwwroot/js/word-companion-host.js @@ -215,6 +215,11 @@ let characterAliasCache = []; let lastSuggestedSceneId = null; let lastSuggestedCharacterSignature = ""; + let assetAliasCacheProjectId = null; + let assetAliasCacheDocumentGuid = ""; + let assetAliasCache = []; + let lastSuggestedAssetSceneId = null; + let lastSuggestedAssetSignature = ""; let lastFollowSceneNotificationSignature = ""; let lastLinkedSceneTitle = ""; let lastLinkedChapterTitle = ""; @@ -577,6 +582,7 @@ plotDirectorStructureCache = null; plotDirectorStructureBookId = null; resetRuntimeCharacterAliasCache(); + resetRuntimeAssetAliasCache(); setRuntimeBookContext(null); }; @@ -2983,10 +2989,13 @@ return false; } - setDocumentMessage("Reading manuscript position..."); + setDocumentMessage("Reading manuscript position..."); try { clearPlotDirectorStructureCache(); - await loadRuntimeCharacterAliases(true); + await Promise.all([ + loadRuntimeCharacterAliases(true), + loadRuntimeAssetAliases(true) + ]); await getBookStructureChapters(book.bookId); const structure = await window.Word.run(async (context) => await readRuntimeDocumentStructure(context, !!book.usesExplicitScenes)); renderOutline(structure); @@ -3896,6 +3905,14 @@ clearPendingCharacterSuggestionDetection(); }; + const resetRuntimeAssetAliasCache = () => { + assetAliasCacheProjectId = null; + assetAliasCacheDocumentGuid = ""; + assetAliasCache = []; + lastSuggestedAssetSceneId = null; + lastSuggestedAssetSignature = ""; + }; + const loadRuntimeCharacterAliases = async (force = false) => { const project = selectedProject(); const documentGuid = currentDocumentGuid(); @@ -3919,6 +3936,29 @@ return characterAliasCache; }; + const loadRuntimeAssetAliases = async (force = false) => { + const project = selectedProject(); + const documentGuid = currentDocumentGuid(); + if (!project || !documentGuid) { + assetAliasCache = []; + return []; + } + + if (!force + && assetAliasCacheProjectId === project.projectId + && assetAliasCacheDocumentGuid === documentGuid + && assetAliasCache.length > 0) { + return assetAliasCache; + } + + const response = await fetchJson(`/api/word-companion/runtime/assets?projectId=${encodeURIComponent(project.projectId)}&documentGuid=${encodeURIComponent(documentGuid)}`); + assetAliasCacheProjectId = project.projectId; + assetAliasCacheDocumentGuid = documentGuid; + assetAliasCache = Array.isArray(response?.assets) ? response.assets : []; + runtimeDebug(`Asset cache loaded: ${assetAliasCache.length} aliases.`); + return assetAliasCache; + }; + const escapeRegex = (value) => String(value || "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const hasWholeWordMatch = (text, matchText) => { @@ -3951,6 +3991,26 @@ return [...detected.entries()].map(([characterId, name]) => ({ characterId, name })); }; + const detectAssetsInSceneText = (sceneText, aliases) => { + if (!sceneText || !Array.isArray(aliases) || aliases.length === 0) { + return []; + } + + const detected = new Map(); + for (const item of aliases) { + const assetId = Number.parseInt(item.assetId || "", 10); + if (!Number.isInteger(assetId) || assetId <= 0 || detected.has(assetId)) { + continue; + } + + if (hasWholeWordMatch(sceneText, item.matchText)) { + detected.set(assetId, item.name || item.matchText || "Asset"); + } + } + + return [...detected.entries()].map(([assetId, name]) => ({ assetId, name })); + }; + const finishCharacterSuggestionDetection = () => { characterSuggestionInFlight = false; if (characterSuggestionPending) { @@ -3975,34 +4035,58 @@ characterSuggestionPending = false; try { - const [sceneText, aliases] = await Promise.all([ + const [sceneText, characterAliases, assetAliases] = await Promise.all([ readCachedCurrentSceneText(), - loadRuntimeCharacterAliases() + loadRuntimeCharacterAliases(), + loadRuntimeAssetAliases() ]); - const detected = detectCharactersInSceneText(sceneText, aliases); + const detected = detectCharactersInSceneText(sceneText, characterAliases); const characterIds = detected.map((item) => item.characterId); const signature = characterIds.slice().sort((left, right) => left - right).join(","); + const detectedAssets = detectAssetsInSceneText(sceneText, assetAliases); + const assetIds = detectedAssets.map((item) => item.assetId); + const assetSignature = assetIds.slice().sort((left, right) => left - right).join(","); + if (!signature || (lastSuggestedSceneId === resolvedSceneId && lastSuggestedCharacterSignature === signature)) { runtimeDebug("Character suggestions skipped."); - return; + } else { + const response = await postJson("/api/word-companion/runtime/character-suggestions", { + documentGuid: currentDocumentGuid(), + sceneId: resolvedSceneId, + characterIds + }); + + lastSuggestedSceneId = resolvedSceneId; + lastSuggestedCharacterSignature = signature; + if ((response?.createdCount || 0) > 0) { + const names = detected.slice(0, 3).map((item) => item.name).join(", "); + const suffix = detected.length > 3 ? ` +${detected.length - 3}` : ""; + setDocumentMessage(names ? `Characters detected: ${names}${suffix}` : response.message); + } + runtimeDebug(response?.message || "Character suggestions submitted."); } - const response = await postJson("/api/word-companion/runtime/character-suggestions", { - documentGuid: currentDocumentGuid(), - sceneId: resolvedSceneId, - characterIds - }); + if (!assetSignature || (lastSuggestedAssetSceneId === resolvedSceneId && lastSuggestedAssetSignature === assetSignature)) { + runtimeDebug("Asset suggestions skipped."); + } else { + runtimeDebug(`Asset matches found: ${detectedAssets.map((item) => item.name).join(", ")}`); + const assetResponse = await postJson("/api/word-companion/runtime/asset-suggestions", { + documentGuid: currentDocumentGuid(), + sceneId: resolvedSceneId, + assetIds + }); - lastSuggestedSceneId = resolvedSceneId; - lastSuggestedCharacterSignature = signature; - if ((response?.createdCount || 0) > 0) { - const names = detected.slice(0, 3).map((item) => item.name).join(", "); - const suffix = detected.length > 3 ? ` +${detected.length - 3}` : ""; - setDocumentMessage(names ? `Characters detected: ${names}${suffix}` : response.message); + lastSuggestedAssetSceneId = resolvedSceneId; + lastSuggestedAssetSignature = assetSignature; + if ((assetResponse?.createdCount || 0) > 0) { + const names = detectedAssets.slice(0, 3).map((item) => item.name).join(", "); + const suffix = detectedAssets.length > 3 ? ` +${detectedAssets.length - 3}` : ""; + setDocumentMessage(names ? `Assets detected: ${names}${suffix}` : assetResponse.message); + } + runtimeDebug(assetResponse?.message || "Asset suggestions submitted."); } - runtimeDebug(response?.message || "Character suggestions submitted."); } catch (error) { - console.error("Unable to detect character suggestions.", error); + console.error("Unable to detect runtime suggestions.", error); setDiagnostics({ lastError: errorText(error) }); } finally { finishCharacterSuggestionDetection(); @@ -4480,7 +4564,10 @@ setRefreshCurrentSceneBusy(true); setSceneTrackingState("Updating..."); try { - await loadRuntimeCharacterAliases(true); + await Promise.all([ + loadRuntimeCharacterAliases(true), + loadRuntimeAssetAliases(true) + ]); const scanned = await refreshDocumentStructure(); if (!scanned) { return; diff --git a/PlotLine/wwwroot/js/word-companion-host.min.js b/PlotLine/wwwroot/js/word-companion-host.min.js index 46ea721..2b96691 100644 --- a/PlotLine/wwwroot/js/word-companion-host.min.js +++ b/PlotLine/wwwroot/js/word-companion-host.min.js @@ -1 +1 @@ -(()=>{const e="plotdirector.word.projectId",t="plotdirector.word.bookId",n="plotdirector.word.activeTab",r="plotdirector.word.documentGuid",a="plotdirector.word.boundBookId",o="plotdirector.word.boundProjectId",c="plotdirector.word.bindingVersion",i=new Set(["scene","links","structure","diagnostics"]),s=document.querySelector(".word-companion-shell"),d=document.querySelector(".word-companion-tabs"),l=[...document.querySelectorAll("[data-tab-button]")],u=[...document.querySelectorAll("[data-tab-panel]")],p=document.querySelector("[data-first-run-wizard]"),h=document.querySelector("[data-first-run-project-select]"),m=document.querySelector("[data-first-run-book-select]"),y=document.querySelector("[data-first-run-new-book-title]"),w=document.querySelector("[data-first-run-create-book]"),f=document.querySelector("[data-first-run-scan]"),g=document.querySelector("[data-first-run-cancel]"),S=document.querySelector("[data-first-run-status]"),I=document.querySelector("[data-first-run-summary]"),C=document.querySelector("[data-first-run-character-section]"),b=document.querySelector("[data-first-run-character-status]"),k=document.querySelector("[data-first-run-character-candidates]"),v=document.querySelector("[data-first-run-character-actions]"),x=document.querySelector("[data-first-run-create-characters]"),E=document.querySelector("[data-first-run-skip-characters]"),N=document.querySelector("[data-first-run-continue]"),L=document.querySelector("[data-first-run-import-actions]"),P=document.querySelector("[data-first-run-import]"),q=document.querySelector("[data-first-run-import-cancel]"),D=document.querySelector("[data-first-run-replace-dialog]"),A=document.querySelector("[data-first-run-replace-confirm]"),$=document.querySelector("[data-first-run-replace-cancel]"),T=document.querySelector("[data-office-status]"),j=document.querySelector("[data-connection-status]"),W=document.querySelector("[data-summary-connection]"),R=document.querySelector("[data-summary-project]"),U=document.querySelector("[data-summary-book]"),M=document.querySelector("[data-project-select]"),O=document.querySelector("[data-book-select]"),H=document.querySelector("[data-project-message]"),B=document.querySelector("[data-book-message]"),G=document.querySelector("[data-refresh-current-scene]"),F=document.querySelector("[data-refresh-document]"),V=document.querySelector("[data-current-chapter]"),J=document.querySelector("[data-current-scene]"),Y=document.querySelector("[data-current-word-count]"),_=document.querySelector("[data-scene-tracking-status]"),z=document.querySelector("[data-document-message]"),K=document.querySelector("[data-sync-note]"),Q=document.querySelector("[data-document-outline]"),X=document.querySelector("[data-analyse-manuscript-structure]"),Z=document.querySelector("[data-apply-structure-sync]"),ee=document.querySelector("[data-structure-preview-status]"),te=document.querySelector("[data-structure-preview-results]"),ne=document.querySelector("[data-refresh-plotdirector-scene]"),re=document.querySelector("[data-plotdirector-scene-status]"),ae=document.querySelector("[data-anchor-status]"),oe=document.querySelector("[data-anchor-book-id]"),ce=document.querySelector("[data-anchor-chapter-id]"),ie=document.querySelector("[data-anchor-scene-id]"),se=document.querySelector("[data-attach-plotdirector-ids]"),de=document.querySelector("[data-plotdirector-scene-details]"),le=document.querySelector("[data-plotdirector-scene-title]"),ue=document.querySelector("[data-plotdirector-revision-status]"),pe=document.querySelector("[data-plotdirector-estimated-words]"),he=document.querySelector("[data-plotdirector-actual-words]"),me=document.querySelector("[data-plotdirector-blocked-status]"),ye=document.querySelector("[data-plotdirector-blocked-reason-row]"),we=document.querySelector("[data-plotdirector-blocked-reason]"),fe=document.querySelector("[data-runtime-last-sync]"),ge=document.querySelector("[data-sync-scene-progress]"),Se=document.querySelector("[data-sync-word-count]"),Ie=document.querySelector("[data-sync-plotdirector-count]"),Ce=document.querySelector("[data-sync-last-synced]"),be=document.querySelector("[data-sync-status]"),ke=document.querySelector("[data-writing-brief-block]"),ve=document.querySelector("[data-writing-brief]"),xe=document.querySelector("[data-plotdirector-link-groups]"),Ee=document.querySelector("[data-character-chips]"),Ne=document.querySelector("[data-asset-chips]"),Le=(document.querySelector("[data-location-chips]"),document.querySelector("[data-primary-location-select]")),Pe=document.querySelector("[data-save-scene-links]"),qe=document.querySelector("[data-scene-links-status]"),De=document.querySelector("[data-links-editing-scene]"),Ae=document.querySelector("[data-chapter-create-link]"),$e=document.querySelector("[data-chapter-create-link-chapter]"),Te=document.querySelector("[data-create-plotdirector-chapter]"),je=document.querySelector("[data-link-existing-chapter]"),We=document.querySelector("[data-chapter-create-link-status]"),Re=document.querySelector("[data-scene-create-link]"),Ue=document.querySelector("[data-create-link-chapter]"),Me=document.querySelector("[data-create-link-scene]"),Oe=document.querySelector("[data-create-plotdirector-scene]"),He=document.querySelector("[data-link-existing-scene]"),Be=document.querySelector("[data-create-link-status]"),Ge=document.querySelector("[data-link-existing-dialog]"),Fe=document.querySelector("[data-link-scene-search]"),Ve=document.querySelector("[data-link-scene-options]"),Je=document.querySelector("[data-link-selected-scene]"),Ye=document.querySelector("[data-link-dialog-cancel]"),_e=document.querySelector("[data-link-dialog-status]"),ze=document.querySelector("[data-create-scene-dialog]"),Ke=document.querySelector("[data-create-dialog-scene]"),Qe=document.querySelector("[data-create-dialog-chapter]"),Xe=document.querySelector("[data-create-dialog-confirm]"),Ze=document.querySelector("[data-create-dialog-cancel]"),et=document.querySelector("[data-link-existing-chapter-dialog]"),tt=document.querySelector("[data-link-chapter-search]"),nt=document.querySelector("[data-link-chapter-options]"),rt=document.querySelector("[data-link-selected-chapter]"),at=document.querySelector("[data-link-chapter-dialog-cancel]"),ot=document.querySelector("[data-link-chapter-dialog-status]"),ct=document.querySelector("[data-create-chapter-dialog]"),it=document.querySelector("[data-create-chapter-dialog-chapter]"),st=document.querySelector("[data-create-chapter-dialog-book]"),dt=document.querySelector("[data-create-chapter-dialog-confirm]"),lt=document.querySelector("[data-create-chapter-dialog-cancel]"),ut=document.querySelector("[data-apply-structure-sync-dialog]"),pt=document.querySelector("[data-apply-structure-sync-summary]"),ht=document.querySelector("[data-apply-structure-sync-confirm]"),mt=document.querySelector("[data-apply-structure-sync-cancel]"),yt=document.querySelector("[data-resolve-project-id]"),wt=document.querySelector("[data-resolve-project-title]"),ft=document.querySelector("[data-resolve-book-id]"),gt=document.querySelector("[data-resolve-book-title]"),St=document.querySelector("[data-resolve-detected-chapter]"),It=document.querySelector("[data-resolve-detected-scene]"),Ct=document.querySelector("[data-resolve-request-chapter]"),bt=document.querySelector("[data-resolve-request-scene]"),kt=document.querySelector("[data-resolve-result]"),vt=document.querySelector("[data-resolve-chapter-id]"),xt=document.querySelector("[data-resolve-scene-id]"),Et=document.querySelector("[data-run-diagnostics]"),Nt=document.querySelector("[data-diagnostic-host]"),Lt=document.querySelector("[data-diagnostic-platform]"),Pt=document.querySelector("[data-diagnostic-ready]"),qt=document.querySelector("[data-diagnostic-word-api]"),Dt=document.querySelector("[data-diagnostic-last-scan]"),At=document.querySelector("[data-diagnostic-last-error]"),$t=document.querySelector("[data-diagnostic-anchor-type]"),Tt=document.querySelector("[data-diagnostic-stored-scene-id]"),jt=document.querySelector("[data-diagnostic-stored-chapter-id]"),Wt=document.querySelector("[data-diagnostic-resolution-method]"),Rt=document.querySelector("[data-diagnostic-paragraphs]"),Ut=document.querySelector("[data-diagnostic-heading1]"),Mt=document.querySelector("[data-diagnostic-heading2]"),Ot="true"===s?.dataset.authenticated;let Ht=[],Bt=[],Gt=!1,Ft=!1,Vt="Unknown",Jt="Unknown",Yt="",_t="",zt=null,Kt=null,Qt=null,Xt=null,Zt=null,en=null,tn="",nn="Title Match",rn=!1,an=[],on=null,cn=null,sn=[],dn=null,ln=null,un=null,pn=null,hn=null,mn=null,yn=null,wn=null,fn=null,gn=null,Sn=[],In=!1,Cn=!1,bn=0,kn=!1,vn=!1,xn=!1,En=null,Nn="Manual",Ln=!1,Pn=null,qn=!1,Dn=0,An=!1;const $n=1200;let Tn=!1,jn=!1,Wn=null,Rn=!1,Un=!1,Mn=null,On=null,Hn=null,Bn=!1,Gn=!1,Fn=null,Vn="",Jn=[],Yn=null,_n="",zn="",Kn="",Qn="",Xn=0,Zn={characters:[],assets:[],locations:[],primaryLocationId:null};const er=e=>{const t=Date.now();t-Xn<1e3||(Xn=t,console.debug(`[Word Companion Runtime] ${e}`))},tr=e=>{T&&(T.textContent=e)},nr=(e,t=!0)=>{const r=i.has(e)&&l.some(t=>t.dataset.tabButton===e)?e:"scene";for(const e of l){const t=e.dataset.tabButton===r;e.classList.toggle("is-active",t),e.setAttribute("aria-selected",t?"true":"false")}for(const e of u){const t=e.dataset.tabPanel===r;e.classList.toggle("is-active",t),e.hidden=!t}t&&((e,t)=>{try{t?window.localStorage.setItem(e,String(t)):window.localStorage.removeItem(e)}catch{}})(n,r)},rr=()=>{const e=(e=>{try{return window.localStorage.getItem(e)||""}catch{return""}})(n);nr(i.has(e)?e:"scene",!1)},ar=e=>{j&&(j.textContent=e),W&&(W.textContent=e)},or=e=>{H&&(H.textContent=e)},cr=e=>{B&&(B.textContent=e)},ir=e=>{z&&(z.textContent=e)},sr=e=>{re&&(re.textContent=e)},dr=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("anchorType")&&Xr($t,Er(e.anchorType)),t("storedSceneId")&&Xr(Tt,Er(e.storedSceneId)),t("storedChapterId")&&Xr(jt,Er(e.storedChapterId)),t("resolutionMethod")&&Xr(Wt,Er(e.resolutionMethod))},lr=()=>{const e=sa(),t=Number.isInteger(Zt)&&Zt>0&&Xt===Zt,n=!Number.isInteger(en)||en<=0||Qt===en,r=t&&n;Xr(ae,r?"Attached to PlotDirector":"Not attached"),Xr(oe,e?.bookId?String(e.bookId):"-"),Xr(ce,Number.isInteger(en)&&en>0?String(en):"-"),Xr(ie,Number.isInteger(Zt)&&Zt>0?String(Zt):"-"),se&&(se.disabled=!Zt||r&&!rn,se.textContent=Xt&&!r?"Reattach PlotDirector IDs":"Attach PlotDirector IDs"),dr({anchorType:nn||"Title Match",storedSceneId:Xt,storedChapterId:Qt,resolutionMethod:tn})},ur=(e,t,n,r=null,a=null,o=null)=>{const c=e||"",i=t||"",s=Number.isInteger(n)?n:null,d=Number.isInteger(o)&&o>0?o:null,l=Number.isInteger(r)&&r>0?r:null,u=Number.isInteger(a)&&a>0?a:null,p=Yt===c&&_t===i&&zt===s&&Kt===d&&Qt===l&&Xt===u;Yt=e||"",_t=t||"",zt=Number.isInteger(n)?n:null,Kt=Number.isInteger(o)&&o>0?o:null,Qt=Number.isInteger(r)&&r>0?r:null,Xt=Number.isInteger(a)&&a>0?a:null,p||(V&&(V.textContent=e||"Not detected"),J&&(J.textContent=t||"Not detected"),Y&&(Y.textContent=Number.isInteger(n)?String(n):"-"),Xr(Se,Number.isInteger(n)?String(n):"-"),lr())},pr=()=>{Wn&&(window.clearTimeout(Wn),Wn=null)},hr=(e,t)=>{e&&(e.hidden=t)},mr=e=>{Xr(be,e)},yr=e=>{Xr(ee,e)},wr=(e="Select a project and book to analyse manuscript structure.")=>{if(un=null,te){te.innerHTML="";const e=document.createElement("p");e.textContent="No preview generated.",te.append(e)}yr(e),gr()},fr=(e=un)=>((e=un)=>Wa.flatMap(t=>Array.isArray(e?.[t.key])?e[t.key]:[]))(e).filter(e=>"couldLink"===e.category||"wouldCreateChapters"===e.category||"wouldCreateScenes"===e.category),gr=()=>{Z&&(Z.disabled=xn||0===fr().length)},Sr=()=>{X&&(X.disabled=xn||!ia()||!sa()),gr()},Ir=()=>{De&&(De.textContent=Zt?`Editing links for: ${Kn||_t||"Current scene"}`:"Link a PlotDirector scene first.")},Cr=()=>{const e=Ln||!Zt,t=e||!en||Rn;ge&&(ge.disabled=t),Pe&&(Pe.disabled=e),Le&&(Le.disabled=e);for(const t of[Ee,Ne])for(const n of t?[...t.querySelectorAll("input[type='checkbox']")]:[])n.disabled=e},br=e=>{"Live"!==e&&"Manual"!==e||(Nn=e),Xr(_,e||Nn||"Manual")},kr=(e,t="")=>{Ln=!!e,Ln&&(pr(),Lo()),Xr(_,Ln?"Stale":Nn),Cr(),t&&(ir(t),Dr(t))},vr=(e,t=null,n="")=>{Zt=Number.isInteger(e)&&e>0?e:null,en=Number.isInteger(t)&&t>0?t:null,tn=n||"",Zt!==Mn&&(On=null),Zt||(pr(),Lo()),Cr(),mr(Ln?"Refresh Current Scene before syncing.":Zt?"Ready to sync.":"No resolved PlotDirector scene."),Dr(Ln?"Refresh Current Scene before saving.":Zt?"Ready to save.":"Link a PlotDirector scene first."),Ir(),lr()},xr=e=>{G&&(G.disabled=e,G.textContent=e?"Refreshing...":"Refresh Current Scene")},Er=e=>null==e||""===e?"-":String(e),Nr=e=>{if(!e)return"-";const t=e instanceof Date?e:new Date(e);if(Number.isNaN(t.getTime()))return"-";const n=new Date;return`Last synced: ${t.toDateString()===n.toDateString()?"Today":t.toLocaleDateString()} ${t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}`},Lr=e=>{hn=e||null;const t=hn?.lastSyncUtc||hn?.manuscriptDocument?.lastSyncUtc;Xr(fe,Nr(t)),Xr(Ce,Nr(t))},Pr=()=>{mn=null,yn=null,wn=null,Po(),Lr(null)},qr=()=>{yn=null,wn=null},Dr=e=>{Xr(qe,e)},Ar=e=>{Xr(Be,e)},$r=e=>{Xr(We,e)},Tr=()=>!!sa()&&!!Yt&&!en,jr=()=>!!sa()&&!!_t&&Number.isInteger(en)&&en>0,Wr=()=>{hr(Ae,!0),$r(""),Te&&(Te.disabled=!0,Te.textContent="Create Chapter in PlotDirector"),je&&(je.disabled=!0,je.textContent="Link to Existing Chapter")},Rr=(e="")=>{Xr($e,Er(Yt)),hr(Ae,!1),$r(e);const t=Tr();Te&&(Te.disabled=!t,Te.textContent="Create Chapter in PlotDirector"),je&&(je.disabled=!t,je.textContent="Link to Existing Chapter")},Ur=()=>{hr(Re,!0),Ar(""),Oe&&(Oe.disabled=!0,Oe.textContent="Create Scene in PlotDirector"),He&&(He.disabled=!0,He.textContent="Link to Existing Scene")},Mr=(e="")=>{Xr(Ue,Er(Yt)),Xr(Me,Er(_t)),hr(Re,!1),Ar(e);const t=jr();Oe&&(Oe.disabled=!t,Oe.textContent="Create Scene in PlotDirector"),He&&(He.disabled=!t,He.textContent="Link to Existing Scene")},Or=e=>{sr(e),hr(de,!0),hr(ke,!0),hr(xe,!1),Wr(),Ur(),tn="",Kn="",Qn="",nn=Xt?"SceneID Anchor":Qt?"ChapterID Anchor":"Title Match",rn=!1,Zn={characters:[],assets:[],locations:[],primaryLocationId:null},Br(Ee,[],"character"),Br(Ne,[],"asset"),Gr([],null,!1),vr(null),Xr(Ie,"-"),Xr(le,"-"),Xr(ue,"-"),Xr(pe,"-"),Xr(he,"-"),Xr(me,"-"),Xr(we,"-"),hr(ye,!0),lr(),Ir()},Hr=(e,t)=>"asset"===t?e?.assetId||e?.AssetId||e?.storyAssetId||e?.StoryAssetId||0:"location"===t?e?.locationId||e?.LocationId||0:e?.characterId||e?.CharacterId||0,Br=(e,t,n,r=!1)=>{if(!e)return;e.innerHTML="";const a=Array.isArray(t)?t:[];if(0===a.length){const t=document.createElement("p");return t.className="word-companion-empty-list",t.textContent="None",void e.append(t)}for(const t of a){const a=Number.parseInt(Hr(t,n),10);if(!Number.isInteger(a)||a<=0)continue;const o=document.createElement("label");o.className="word-companion-check-item";const c=document.createElement("input");c.type="checkbox",c.value=String(a),c.checked=!!t.linked,c.disabled=!r;const i=document.createElement("span");i.textContent=t.name||"Unnamed",o.append(c,i),e.append(o)}},Gr=(e,t,n=!1)=>{if(!Le)return;Le.innerHTML="";const r=document.createElement("option");r.value="",r.textContent="None",Le.append(r);const a=Number.parseInt(t||"",10);for(const t of Array.isArray(e)?e:[]){const e=Number.parseInt(Hr(t,"location"),10);if(!Number.isInteger(e)||e<=0)continue;const n=document.createElement("option");n.value=String(e),n.textContent=t.name||"Unnamed",n.selected=e===a,Le.append(n)}Le.disabled=!n},Fr=e=>String(e||"").trim().replace(/\s+/g," "),Vr=(e,t)=>{const n=Fr(e);if(!n)return"";const r=new RegExp(`^${"scene"===t?"scene":"chapter"}\\s+(?:\\d+|[ivxlcdm]+|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)\\s*(?::|-|\\u2013|\\u2014)\\s*`,"i");return Fr(n.replace(r,""))||n},Jr=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("projectId")&&Xr(yt,Er(e.projectId)),t("projectTitle")&&Xr(wt,Er(e.projectTitle)),t("bookId")&&Xr(ft,Er(e.bookId)),t("bookTitle")&&Xr(gt,Er(e.bookTitle)),t("detectedChapter")&&Xr(St,Er(e.detectedChapter)),t("detectedScene")&&Xr(It,Er(e.detectedScene)),t("requestChapter")&&Xr(Ct,Er(e.requestChapter)),t("requestScene")&&Xr(bt,Er(e.requestScene)),t("result")&&Xr(kt,Er(e.result)),t("chapterId")&&Xr(vt,Er(e.chapterId)),t("sceneId")&&Xr(xt,Er(e.sceneId))},Yr=async e=>{if(wn===e&&Array.isArray(yn?.chapters))return yn.chapters;const t=await co(`/api/word-companion/books/${e}/structure`);return wn=e,yn=t||null,Array.isArray(t?.chapters)?t.chapters:[]},_r=async e=>{const t=await co(`/api/word-companion/books/${e}/chapters`);return Array.isArray(t?.chapters)?t.chapters:[]},zr=e=>{if(Number.isInteger(en)&&en>0){const t=e.find(e=>e.chapterId===en);if(t)return t}const t=Vr(Yt,"chapter").toLocaleLowerCase();return t&&e.find(e=>Vr(e.title,"chapter").toLocaleLowerCase()===t)||null},Kr=async()=>{const e=sa();return e?zr(await Yr(e.bookId)):null},Qr=async(e,t,n,r,a)=>{const o=await co(`/api/word-companion/scenes/${t}/companion`);try{o.revisionStatus=await(async(e,t)=>{const n=await co(`/api/word-companion/books/${e}/structure`),r=Array.isArray(n?.chapters)?n.chapters:[];for(const e of r){const n=(Array.isArray(e.scenes)?e.scenes:[]).find(e=>e.sceneId===t);if(n)return n.revisionStatus||""}return""})(e,t)}catch{o.revisionStatus=""}var c;nn=a||"Title Match",rn=!1,kr(!1),sr("Linked to PlotDirector"),ir(""),Wr(),Ur(),vr(t,n,r),c=o,Kn=c?.sceneTitle||_t||"",Qn=c?.chapterTitle||Yt||"",Xr(le,Er(c?.sceneTitle)),Xr(ue,Er(c?.revisionStatus||c?.revisionStatusName||"Not provided")),Xr(pe,Er(c?.estimatedWords)),Xr(he,Er(c?.actualWords)),Xr(Ie,Er(c?.actualWords)),Xr(me,c?.blocked?"Blocked":"Not blocked"),c?.blockedReason?(Xr(we,c.blockedReason),hr(ye,!1)):(Xr(we,"-"),hr(ye,!0)),ve&&(ve.textContent=c?.writingBrief||"No writing brief has been added for this scene."),Zn={characters:Array.isArray(c?.characters)?c.characters:[],assets:Array.isArray(c?.assets)?c.assets:[],locations:Array.isArray(c?.locations)?c.locations:[],primaryLocationId:c?.primaryLocationId??null},Br(Ee,Zn.characters,"character",!!Zt&&!Ln),Br(Ne,Zn.assets,"asset",!!Zt&&!Ln),Gr(Zn.locations,Zn.primaryLocationId,!!Zt&&!Ln),Ir(),Dr(Ln?"Refresh Current Scene before saving.":Zt?"Ready to save.":"No resolved PlotDirector scene."),hr(de,!1),hr(ke,!1),hr(xe,!1),lo(t,n),No(),$o()},Xr=(e,t)=>{if(e){const n=null==t?"":String(t);e.textContent!==n&&(e.textContent=n)}},Zr=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("host")&&Xr(Nt,e.host),t("platform")&&Xr(Lt,e.platform),t("ready")&&Xr(Pt,e.ready),t("wordApi")&&Xr(qt,e.wordApi),t("lastScan")&&Xr(Dt,e.lastScan),t("lastError")&&Xr(At,e.lastError),t("paragraphs")&&Xr(Rt,e.paragraphs),t("heading1")&&Xr(Ut,e.heading1),t("heading2")&&Xr(Mt,e.heading2)},ea=e=>{const t=[];return e?.name&&t.push(e.name),e?.code&&e.code!==e.name&&t.push(e.code),e?.message&&t.push(e.message),e?.debugInfo?.errorLocation&&t.push(`Location: ${e.debugInfo.errorLocation}`),t.length>0?t.join(": "):String(e)},ta=async()=>{if(!window.Office||"function"!=typeof window.Office.onReady)return Gt=!1,Ft=!1,Vt="Unavailable",Jt="Unavailable",Zr({host:Vt,platform:Jt,ready:"No",wordApi:"No"}),null;const e=await window.Office.onReady();return Gt=!0,Vt=e?.host||"Unknown",Jt=e?.platform||"Unknown",Ft=!!window.Word&&!!window.Office.HostType&&e?.host===window.Office.HostType.Word,Zr({host:Vt,platform:Jt,ready:"Yes",wordApi:Ft?"Yes":"No"}),e},na=e=>{try{const t=window.localStorage.getItem(e),n=Number.parseInt(t||"",10);return Number.isInteger(n)&&n>0?n:null}catch{return null}},ra=(e,t)=>{try{t?window.localStorage.setItem(e,String(t)):window.localStorage.removeItem(e)}catch{}},aa=(e,t)=>{if(!e)return;e.innerHTML="";const n=document.createElement("option");n.value="",n.textContent=t,e.append(n),e.disabled=!0},oa=(e,t,n,r,a)=>{if(!e)return;e.innerHTML="";const o=document.createElement("option");o.value="",o.textContent=t,e.append(o);for(const t of n){const n=document.createElement("option");n.value=String(t[r]),n.textContent=t[a],e.append(n)}e.disabled=0===n.length},ca=e=>{const t=String(e?.title||"").trim(),n=String(e?.subtitle||"").trim();return n?`${t}: ${n}`:t},ia=()=>{const e=Number.parseInt(M?.value||"",10);return Ht.find(t=>t.projectId===e)||null},sa=()=>{const e=Number.parseInt(O?.value||"",10);return Bt.find(t=>t.bookId===e)||null},da=()=>{const e=Number.parseInt(h?.value||"",10);return Ht.find(t=>t.projectId===e)||null},la=()=>{const e=Number.parseInt(m?.value||"",10);return Bt.find(t=>t.bookId===e)||null},ua=e=>Xr(S,e),pa=()=>{const e=da(),t=la(),n=Cn&&Date.now()-bn>=750;f&&(f.disabled=!e||!t||kn),w&&(w.disabled=!e||!String(y?.value||"").trim()||kn),P&&(P.disabled=!fn?.canImport||!gn||kn),x&&(x.disabled=!n||vn||0===wa().length)},ha=e=>{hr(p,!e),hr(d,e);for(const t of u)hr(t,!!e||"scene"!==t.dataset.tabPanel&&!t.classList.contains("is-active"));e||rr()},ma=()=>{if(!h)return;if(0===Ht.length)return void aa(h,"No projects available.");oa(h,"Choose a project",Ht,"projectId","title");const e=Number.parseInt(M?.value||"",10);Number.isInteger(e)&&e>0&&(h.value=String(e))},ya=(e="Select a Project and Book to begin.")=>{fn=null,gn=null,Sn=[],In=!1,Cn=!1,bn=0,hr(I,!0),hr(L,!0),hr(C,!0),hr(v,!0),I&&(I.innerHTML=""),k&&(k.innerHTML=""),Xr(b,""),ua(e),pa()},wa=()=>k?[...k.querySelectorAll("input[type='checkbox']:checked")].map(e=>String(e.value||"").trim()).filter(Boolean):[],fa=e=>{if(Sn=Array.isArray(e)?e:[],C&&k){if(k.innerHTML="",hr(C,!1),hr(v,!In||0===Sn.length),hr(x,!1),hr(E,!1),hr(N,!0),0===Sn.length)return Xr(b,"No likely major characters found."),void pa();Xr(b,`${Sn.length} likely major characters found.`);for(const e of Sn){const t=document.createElement("label");t.className="word-companion-character-candidate";const n=document.createElement("input");n.type="checkbox",n.value=e.text||"",n.checked="high"===String(e.confidence||"").trim().toLowerCase(),n.addEventListener("change",pa);const r=document.createElement("strong");r.textContent=e.text||"";const a=document.createElement("em"),o=String(e.reason||"").trim();a.textContent=o?`${Number(e.mentionCount||0).toLocaleString()} mentions · ${o}`:`${Number(e.mentionCount||0).toLocaleString()} mentions`;const c=document.createElement("span");c.className="word-companion-character-candidate-text",c.append(r,a),t.append(n,c),k.append(t)}pa()}},ga=()=>{const e=window.Office?.context?.document?.settings;if(!e)return null;const t=String(e.get(r)||"").trim(),n=Number.parseInt(e.get(a)||"",10),i=Number.parseInt(e.get(o)||"",10),s=Number.parseInt(e.get(c)||"",10);return!t||!Number.isInteger(n)||n<=0||!Number.isInteger(i)||i<=0?null:{documentGuid:t,bookId:n,projectId:i,bindingVersion:Number.isInteger(s)&&s>0?s:1}},Sa=()=>pn?.documentGuid?pn.documentGuid:window.crypto?.randomUUID?window.crypto.randomUUID():"10000000-1000-4000-8000-100000000000".replace(/[018]/g,e=>(Number(e)^16*Math.random()>>Number(e)/4).toString(16)),Ia=()=>pn?.documentGuid||ga()?.documentGuid||"",Ca=()=>{const e=ia(),t=sa();R&&(R.textContent=e?.title||"(Not connected)"),U&&(U.textContent=t?ca(t):"(Not connected)"),K&&(K.textContent=t?"":"Select a PlotDirector book before refreshing."),Sr()},ba=e=>String(e?.styleBuiltIn||e?.style||"").replace(/\s+/g,"").toLowerCase(),ka=(e,t)=>{const n=ba(e);return n===`heading${t}`||n.endsWith(`.heading${t}`)||n.includes(`heading${t}`)},va=e=>String(e||"").trim().split(/\s+/).filter(Boolean).length,xa=(e,t)=>{const n=String(e||"").match(new RegExp(`^${t}-(\\d+)$`,"i"));if(!n)return null;const r=Number.parseInt(n[1],10);return Number.isInteger(r)&&r>0?r:null},Ea=e=>{try{return Array.isArray(e?.contentControls?.items)?e.contentControls.items:[]}catch(e){return console.warn("Word paragraph content controls were not available.",e),[]}},Na=(e,t)=>{const n=Ea(e);for(const e of n){const n=xa(e.tag,t);if(n)return n}return null},La=(e,t)=>{const n=[];let r=0,a=0,o=null,c=null;e.forEach((e,t)=>{const i=String(e.text||"").trim();if(i){if(ka(e,1))return r+=1,o={index:n.length+1,paragraphIndex:t,title:i,anchorId:Na(e,"PD-CHAPTER"),scenes:[]},n.push(o),void(c=null);if(ka(e,2)){if(a+=1,!o)return;return c={index:o.scenes.length+1,paragraphIndex:t,title:i,anchorId:Na(e,"PD-SCENE"),wordCount:0},void o.scenes.push(c)}c&&(c.wordCount+=va(i))}});const i=t.find(e=>String(e.text||"").trim()),s=i?e.findIndex(e=>{return t=e,n=i,String(t?.text||"").trim()===String(n?.text||"").trim()&&ba(t)===ba(n);var t,n}):-1,d=s>=0&&n.filter(e=>e.paragraphIndex<=s).at(-1)||null,l=d&&s>=0&&d.scenes.filter(e=>e.paragraphIndex<=s).at(-1)||null;return{chapters:n,currentChapter:d,currentScene:l,paragraphCount:e.length,heading1Count:r,heading2Count:a}},Pa=new Set(["***","###"]),qa=(e,t)=>{const n=String(e?.text||"").trim();return{index:t,text:n,styleBuiltIn:e?.styleBuiltIn||"",style:e?.style||"",wordCount:va(n),chapterAnchorId:null,sceneAnchorId:null}},Da=(e,t)=>{e&&(e.endParagraphIndex=t)},Aa=(e,t)=>{e&&(e.endParagraphIndex=t,Da(e.scenes.at(-1),t))},$a=(e,t)=>{const n=(t||[]).find(e=>String(e.text||"").trim());if(!e||!n)return e?.currentParagraphIndex??-1;const r=e.paragraphs.filter(e=>((e,t)=>String(e?.text||"").trim()===String(t?.text||"").trim()&&ba(e)===ba(t))(e,n)).map(e=>e.index);return 0===r.length?e.currentParagraphIndex??-1:Number.isInteger(e.currentParagraphIndex)?r.reduce((t,n)=>Math.abs(n-e.currentParagraphIndex){if(!mn)return!1;const t=((e,t)=>!e||!Number.isInteger(t)||t<0?null:e.chapters.filter(e=>e.startParagraphIndex<=t).at(-1)||null)(mn,e),n=((e,t)=>!e||!Number.isInteger(t)||t<0?null:e.scenes.filter(e=>e.startParagraphIndex<=t).at(-1)||null)(t,e),r=t?.startParagraphIndex!==mn.currentChapter?.startParagraphIndex||n?.startParagraphIndex!==mn.currentScene?.startParagraphIndex||t?.anchorId!==mn.currentChapter?.anchorId||n?.anchorId!==mn.currentScene?.anchorId;return mn.currentParagraphIndex=e,mn.currentChapter=t,mn.currentScene=n,!!r&&(ur(t?.title,n?.title,n?.wordCount,t?.anchorId,n?.anchorId,t?.index),r)},ja=e=>{if(!Q)return;if(Q.innerHTML="",0===e.chapters.length){const e=document.createElement("p");return e.textContent="No chapters detected. Use Heading 1 for chapter titles.",void Q.append(e)}if(!e.chapters.some(e=>e.scenes.length>0)){const e=document.createElement("p");e.textContent="No scenes detected. Use Heading 2 for scene titles.",Q.append(e)}for(const t of e.chapters){const e=document.createElement("div");e.className="word-companion-outline-chapter";const n=document.createElement("strong");if(n.textContent=t.title,e.append(n),t.scenes.length>0){const n=document.createElement("ul");for(const e of t.scenes){const t=document.createElement("li");t.textContent=e.title,n.append(t)}e.append(n)}Q.append(e)}},Wa=[{key:"alreadyLinked",title:"Already Linked"},{key:"couldLink",title:"Could Link"},{key:"wouldCreateChapters",title:"Would Create Chapters"},{key:"wouldCreateScenes",title:"Would Create Scenes"},{key:"manualReview",title:"Manual Review Required"}],Ra={alreadyLinked:"Already Linked",couldLink:"Could Link",wouldCreateChapter:"Would Create Chapter",wouldCreateScene:"Would Create Scene",manualReview:"Manual Review Required"},Ua={alreadyLinked:"✓",couldLink:"~",wouldCreateChapter:"+",wouldCreateScene:"+",manualReview:"?"},Ma=(e,t)=>Vr(e,t).toLocaleLowerCase(),Oa=({category:e,action:t,type:n,wordTitle:r,match:a="",anchorStatus:o="None",matches:c=[],pdChapter:i=null,pdScene:s=null,wordChapter:d=null,wordScene:l=null,parentItem:u=null})=>({id:`${n}-${d?.index||0}-${l?.index||0}-${d?.paragraphIndex??l?.paragraphIndex??0}`,category:e,action:t,type:n,wordTitle:r,match:a,anchorStatus:o,matches:c,pdChapter:i,pdScene:s,wordChapter:d,wordScene:l,parentItem:u,result:"Pending",error:""}),Ha=(e,t)=>{Array.isArray(e[t.category])&&e[t.category].push(t)},Ba=e=>Array.isArray(e?.scenes)?e.scenes:[],Ga=(e,t,n)=>{const r=e.anchorId?`PD-CHAPTER-${e.anchorId}`:"None";if(e.anchorId){const a=t.find(t=>t.chapterId===e.anchorId);if(a){const t=Oa({category:"alreadyLinked",action:"alreadyLinked",type:"Chapter",wordTitle:e.title,match:`Chapter ${a.chapterId}: ${a.title}`,anchorStatus:r,pdChapter:a,wordChapter:e});return Ha(n,t),t}const o=Oa({category:"manualReview",action:"manualReview",type:"Chapter",wordTitle:e.title,anchorStatus:`${r} not found`,matches:[],pdChapter:null,wordChapter:e});return Ha(n,o),o}const a=t.filter(t=>Ma(t.title,"chapter")===Ma(e.title,"chapter"));if(1===a.length){const t=Oa({category:"couldLink",action:"couldLink",type:"Chapter",wordTitle:e.title,match:`Chapter ${a[0].chapterId}: ${a[0].title}`,anchorStatus:r,pdChapter:a[0],wordChapter:e});return Ha(n,t),t}if(a.length>1){const t=Oa({category:"manualReview",action:"manualReview",type:"Chapter",wordTitle:e.title,anchorStatus:r,matches:a.map(e=>`Chapter ${e.chapterId}: ${e.title}`),pdChapter:null,wordChapter:e});return Ha(n,t),t}const o=Oa({category:"wouldCreateChapters",action:"wouldCreateChapter",type:"Chapter",wordTitle:e.title,anchorStatus:r,pdChapter:null,wordChapter:e});return Ha(n,o),o},Fa=(e,t,n,r)=>{const a=e.anchorId?`PD-SCENE-${e.anchorId}`:"None";if(e.anchorId){const o=((e,t)=>{for(const n of e){const e=Ba(n).find(e=>e.sceneId===t);if(e)return{chapter:n,scene:e}}return null})(n,e.anchorId);return o?void Ha(r,Oa({category:"alreadyLinked",action:"alreadyLinked",type:"Scene",wordTitle:e.title,match:`Scene ${o.scene.sceneId}: ${o.scene.title}`,anchorStatus:a,pdChapter:o.chapter,pdScene:o.scene,wordChapter:t?.wordChapter,wordScene:e,parentItem:t})):void Ha(r,Oa({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:e.title,anchorStatus:`${a} not found`,wordChapter:t?.wordChapter,wordScene:e,parentItem:t}))}if(!t?.pdChapter&&"manualReview"===t?.category)return void Ha(r,Oa({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:e.title,anchorStatus:a,matches:["Parent chapter requires manual review."],wordChapter:t?.wordChapter,wordScene:e,parentItem:t}));if(!t?.pdChapter)return void Ha(r,Oa({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:e.title,anchorStatus:a,wordChapter:t?.wordChapter,wordScene:e,parentItem:t}));const o=Ba(t.pdChapter).filter(t=>Ma(t.title,"scene")===Ma(e.title,"scene"));1!==o.length?o.length>1?Ha(r,Oa({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:e.title,anchorStatus:a,matches:o.map(e=>`Scene ${e.sceneId}: ${e.title}`),wordChapter:t.wordChapter,wordScene:e,parentItem:t})):Ha(r,Oa({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:e.title,anchorStatus:a,pdChapter:t.pdChapter,wordChapter:t.wordChapter,wordScene:e,parentItem:t})):Ha(r,Oa({category:"couldLink",action:"couldLink",type:"Scene",wordTitle:e.title,match:`Scene ${o[0].sceneId}: ${o[0].title}`,anchorStatus:a,pdChapter:t.pdChapter,pdScene:o[0],wordChapter:t.wordChapter,wordScene:e,parentItem:t}))},Va=e=>{const t=document.createElement("article");t.className="word-companion-preview-item";const n=document.createElement("strong");n.textContent=`${Ua[e.action]||""} ${e.type}: ${e.wordTitle}`,t.append(n);const r=document.createElement("span");if(r.textContent=`Anchor: ${e.anchorStatus||"None"}`,t.append(r),e.match){const n=document.createElement("span");n.textContent=`Match: ${e.match}`,t.append(n)}if(Array.isArray(e.matches)&&e.matches.length>0){const n=document.createElement("div");n.className="word-companion-preview-matches";const r=document.createElement("span");r.textContent="Matches:",n.append(r);const a=document.createElement("ul");for(const t of e.matches){const e=document.createElement("li");e.textContent=t,a.append(e)}n.append(a),t.append(n)}const a=document.createElement("span");if(a.textContent=`Action: ${Ra[e.action]||e.action}`,t.append(a),e.result&&"Pending"!==e.result){const n=document.createElement("span");n.textContent=e.error?`Result: ${e.result} - ${e.error}`:`Result: ${e.result}`,t.append(n)}return t},Ja=e=>{if(te){te.innerHTML="";for(const t of Wa){const n=document.createElement("section");n.className="word-companion-preview-group";const r=document.createElement("strong");r.textContent=t.title,n.append(r);const a=Array.isArray(e?.[t.key])?e[t.key]:[];if(0===a.length){const e=document.createElement("p");e.className="word-companion-empty-list",e.textContent="None",n.append(e)}else for(const e of a)n.append(Va(e));te.append(n)}gr()}},Ya=async e=>{const t=e.document.body.paragraphs,n=e.document.getSelection().paragraphs;t.load("text,styleBuiltIn,style"),n.load("text,styleBuiltIn,style"),await e.sync();try{for(const e of t.items)(ka(e,1)||ka(e,2))&&e.contentControls.load("items/tag,title");await e.sync()}catch(e){console.warn("Unable to load Word heading content controls. Continuing without PlotDirector anchors.",e)}const r=La(t.items,n.items);return r.bodyParagraphs=t.items,r},_a=async(e,t)=>{const n=e.document.body.paragraphs,r=e.document.getSelection().paragraphs;n.load("text,styleBuiltIn,style"),r.load("text,styleBuiltIn,style"),await e.sync();const a=((e,t)=>{const n=e.map(qa),r=[];let a=0,o=0,c=null,i=null,s=0;const d=(e,t=null,n=null)=>c?(Da(i,e.index-1),i={index:c.scenes.length+1,paragraphIndex:e.index,startParagraphIndex:e.index,endParagraphIndex:e.index,title:t||`Scene ${c.scenes.length+1}`,anchorId:n,wordCount:0},c.scenes.push(i),i):null;for(const e of n)e.text&&(ka(e,1)?(Aa(c,e.index-1),a+=1,c={index:r.length+1,paragraphIndex:e.index,startParagraphIndex:e.index,endParagraphIndex:e.index,title:e.text,anchorId:e.chapterAnchorId,wordCount:0,scenes:[]},r.push(c),i=null,d(e,"Scene 1",e.sceneAnchorId),s+=e.wordCount):c&&(t&&Pa.has(e.text)?(o+=1,d(e)):(c.wordCount+=e.wordCount,i&&(i.wordCount+=e.wordCount),s+=e.wordCount)));return Aa(c,n.length-1),{paragraphs:n,chapters:r,usesExplicitScenes:!!t,paragraphCount:n.length,heading1Count:a,heading2Count:o,documentWordCount:s,currentParagraphIndex:null,currentChapter:null,currentScene:null}})(n.items,t),o=$a(a,r.items);return mn=a,Ta(o),er("Cache rebuilt."),a},za=async()=>{const e=mn?.currentScene;return e&&Number.isInteger(e.startParagraphIndex)&&Number.isInteger(e.endParagraphIndex)&&Gt&&Ft&&window.Word&&"function"==typeof window.Word.run?await window.Word.run(async t=>{const n=t.document.body.paragraphs;n.load("text"),await t.sync();let r=0;const a=Math.min(e.endParagraphIndex,n.items.length-1),o=mn.currentChapter?.startParagraphIndex;for(let t=e.startParagraphIndex;t<=a;t+=1){const e=String(n.items[t]?.text||"").trim();e&&!Pa.has(e)&&t!==o&&(r+=va(e))}return e.wordCount=r,ur(mn.currentChapter?.title,e.title,r,mn.currentChapter?.anchorId,e.anchorId,mn.currentChapter?.index),r}):zt},Ka=async()=>{const e=mn?.currentScene;return e&&Number.isInteger(e.startParagraphIndex)&&Number.isInteger(e.endParagraphIndex)&&Gt&&Ft&&window.Word&&"function"==typeof window.Word.run?await window.Word.run(async t=>{const n=t.document.body.paragraphs;n.load("text"),await t.sync();const r=[],a=Math.min(e.endParagraphIndex,n.items.length-1),o=mn.currentChapter?.startParagraphIndex;for(let t=e.startParagraphIndex;t<=a;t+=1){const e=String(n.items[t]?.text||"").trim();e&&!Pa.has(e)&&t!==o&&r.push(e)}return r.join("\n")}):""},Qa=async()=>{if(ir(""),!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return ur(null,null,null),ir("Word document access is unavailable."),Zr({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;F&&(F.disabled=!0,F.textContent="Scanning..."),ir("Scanning document structure...");try{const e=await window.Word.run(async e=>{const t=sa();return t?await _a(e,!!t.usesExplicitScenes):(mn=null,await Ya(e))});return mn||ur(e.currentChapter?.title,e.currentScene?.title,e.currentScene?.wordCount,e.currentChapter?.anchorId,e.currentScene?.anchorId,e.currentChapter?.index),Or("Not detected"),ja(e),ir(""),Zr({lastScan:"Success",lastError:"-",paragraphs:String(e.paragraphCount),heading1:String(e.heading1Count),heading2:String(e.heading2Count)}),!0}catch(e){const t=ea(e);return console.error("Unable to scan the Word document.",e),ur(null,null,null),ir(`Unable to scan the Word document: ${t}`),Zr({lastScan:"Failure",lastError:t}),!1}finally{F&&(F.disabled=!1,F.textContent="Refresh Document Structure")}},Xa=async()=>{const e=sa();if(!ia()||!e)return yr("Select a project and book to analyse manuscript structure."),!1;if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return yr("Word document access is unavailable."),Zr({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;X&&(X.disabled=!0,X.textContent="Analysing..."),yr("Analysing manuscript structure...");try{const t=await window.Word.run(async e=>await Ya(e)),n=await co(`/api/word-companion/books/${e.bookId}/structure`);return ur(t.currentChapter?.title,t.currentScene?.title,t.currentScene?.wordCount,t.currentChapter?.anchorId,t.currentScene?.anchorId,t.currentChapter?.index),ja(t),un=((e,t)=>{const n={alreadyLinked:[],couldLink:[],wouldCreateChapters:[],wouldCreateScenes:[],manualReview:[]},r=Array.isArray(t?.chapters)?t.chapters:[];for(const t of Array.isArray(e?.chapters)?e.chapters:[]){const e=Ga(t,r,n);for(const a of Ba(t))Fa(a,e,r,n)}return n})(t,n),Ja(un),yr("Preview generated. No changes have been applied."),Zr({lastScan:"Success",lastError:"-",paragraphs:String(t.paragraphCount),heading1:String(t.heading1Count),heading2:String(t.heading2Count)}),!0}catch(e){return console.error("Unable to analyse manuscript structure.",e),yr("Unable to analyse manuscript structure."),Zr({lastScan:"Failure",lastError:ea(e)}),!1}finally{X&&(X.textContent="Analyse Manuscript Structure",Sr())}},Za=e=>{En&&(En(e),En=null),ut?.close?ut.close():ut&&(ut.hidden=!0)},eo=()=>{const e=((e=un)=>{const t=fr(e);return{linkChapters:t.filter(e=>"couldLink"===e.category&&"Chapter"===e.type).length,linkScenes:t.filter(e=>"couldLink"===e.category&&"Scene"===e.type).length,createChapters:t.filter(e=>"wouldCreateChapters"===e.category).length,createScenes:t.filter(e=>"wouldCreateScenes"===e.category).length,manualReview:Array.isArray(e?.manualReview)?e.manualReview.length:0}})();return(e=>{if(!pt)return;pt.innerHTML="";const t=[`Link ${e.linkChapters+e.linkScenes} chapters/scenes`,`Create ${e.createChapters} chapters`,`Create ${e.createScenes} scenes`],n=document.createElement("ul");for(const e of t){const t=document.createElement("li");t.textContent=e,n.append(t)}pt.append(n)})(e),ut?new Promise(e=>{En=e,ut.showModal?ut.showModal():ut.hidden=!1}):Promise.resolve(window.confirm(`Apply Structure Sync?\n\nThis will:\n\n- Link ${e.linkChapters+e.linkScenes} chapters/scenes\n- Create ${e.createChapters} chapters\n- Create ${e.createScenes} scenes\n\nManual review items will be skipped.`))},to=(e,t,n="")=>{e.result=t,e.error=n},no=e=>Number.isInteger(e?.wordChapter?.index)&&e.wordChapter.index>0?10*e.wordChapter.index:null,ro=e=>Number.isInteger(e?.wordScene?.index)&&e.wordScene.index>0?10*e.wordScene.index:null,ao=async(e,t)=>{const n=await io(`/api/word-companion/books/${e}/chapters`,{title:Fr(t.wordTitle),sortOrder:no(t)});if(!n?.chapterId)throw new Error("Chapter creation did not return a chapter ID.");qr(),t.pdChapter={chapterId:n.chapterId,title:n.title||t.wordTitle,sortOrder:n.sortOrder||no(t)||0,scenes:[]},t.match=`Chapter ${t.pdChapter.chapterId}: ${t.pdChapter.title}`},oo=async(e,t)=>{const n=t.pdChapter||t.parentItem?.pdChapter;if(!n?.chapterId)throw new Error("Scene parent chapter is not available.");const r=await io(`/api/word-companion/books/${e}/chapters/${n.chapterId}/scenes`,{sceneTitle:Fr(t.wordTitle),sortOrder:ro(t)});if(!r?.sceneId)throw new Error("Scene creation did not return a scene ID.");qr(),t.pdChapter=n,t.pdScene={sceneId:r.sceneId,title:t.wordTitle,sortOrder:ro(t)||0},t.match=`Scene ${t.pdScene.sceneId}: ${t.pdScene.title}`},co=async(e,t={})=>{const n=await window.fetch(e,{credentials:"same-origin",...t,headers:{Accept:"application/json",...t.headers||{}}});if(!n.ok)throw new Error(`Request failed: ${n.status}`);return await n.json()},io=(e,t)=>co(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),so=async(e="")=>{Cn=!1,bn=0,Sn=[],k&&(k.innerHTML=""),hr(C,!0),ha(!1),ua(""),hr(v,!0),e&&ir(e);const t=await uo();e&&t&&Yt&&ir(e)},lo=async(e=Zt,t=en)=>{const n=ia(),r=sa(),a=Ia(),o=Number.parseInt(e||"",10),c=Number.parseInt(t||"",10);if(!n||!r||!a||!Number.isInteger(o)||o<=0||!Number.isInteger(c)||c<=0)return;const i=`${n.projectId}:${r.bookId}:${o}`;if(zn!==i){zn=i;try{await io("/api/word-companion/runtime/current-scene",{documentGuid:a,projectId:n.projectId,bookId:r.bookId,chapterId:c,sceneId:o}),er("Current scene follow event sent.")}catch(e){zn="",console.debug("Unable to notify PlotDirector of current scene.",e)}}},uo=async()=>{const e=sa();if(!(e&&Gt&&Ft&&window.Word&&"function"==typeof window.Word.run))return!1;ir("Reading manuscript position...");try{qr(),await qo(!0),await Yr(e.bookId);const t=await window.Word.run(async t=>await _a(t,!!e.usesExplicitScenes));return ja(t),Zr({lastScan:"Success",lastError:"-",paragraphs:String(t.paragraphCount),heading1:String(t.heading1Count),heading2:String(t.heading2Count)}),Yt?(_t?await jo():await To(),kr(!1),br("Live"),ir(""),!0):(Or("Not detected"),kr(!1),br("Live"),ir("Manuscript linked. Click inside a chapter to show the current scene."),!0)}catch(e){return console.error("Unable to initialise bound manuscript runtime.",e),mn=null,br("Manual"),ir(`Unable to read manuscript position: ${ea(e)}`),Zr({lastScan:"Failure",lastError:ea(e)}),!1}},po=e=>e?[...e.querySelectorAll("input[type='checkbox']:checked")].map(e=>Number.parseInt(e.value||"",10)).filter(e=>Number.isInteger(e)&&e>0):[],ho=()=>{const e=Number.parseInt(Le?.value||"",10);return Number.isInteger(e)&&e>0?e:null},mo=(e,t,n,r)=>{const a=((e,t)=>Ea(e).find(e=>xa(e.tag,t))||null)(e,r),o=a||e.getRange().insertContentControl();return o.title=t,o.tag=n,o.appearance="Hidden",o},yo=async(e="PlotDirector IDs attached successfully.")=>{if(!Zt||!en)return ir("No resolved PlotDirector scene."),!1;if((Xt&&Xt!==Zt||Qt&&Qt!==en)&&!window.confirm("This scene is already linked. Replace the existing PlotDirector link?"))return!1;if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return ir("Word document access is unavailable."),!1;se&&(se.disabled=!0,se.textContent="Attaching...");try{return await window.Word.run(async e=>{const t=await Ya(e);if(!t.currentChapter||!t.currentScene)throw new Error("No scene detected in Word. Use Heading 2 for scenes.");const n=t.bodyParagraphs[t.currentChapter.paragraphIndex],r=t.bodyParagraphs[t.currentScene.paragraphIndex];if(!n||!r)throw new Error("Unable to locate the current Word headings.");mo(n,"PlotDirector Chapter",`PD-CHAPTER-${en}`,"PD-CHAPTER"),mo(r,"PlotDirector Scene",`PD-SCENE-${Zt}`,"PD-SCENE"),await e.sync()}),Qt=en,Xt=Zt,rn=!1,nn="SceneID Anchor",tn="Anchor",ir(e),Zr({lastError:"-"}),lr(),!0}catch(e){return console.error("Unable to attach PlotDirector IDs.",e),ir("Unable to attach PlotDirector IDs."),Zr({lastError:ea(e)}),lr(),!1}finally{se&&(se.textContent=Xt===Zt?"Attach PlotDirector IDs":"Reattach PlotDirector IDs",lr())}},wo=async e=>{if(!en)return $r("No resolved PlotDirector chapter."),!1;if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return $r("Word document access is unavailable."),!1;try{return await window.Word.run(async e=>{const t=await Ya(e);if(!t.currentChapter)throw new Error("No chapter detected in Word. Use Heading 1 for chapters.");const n=t.bodyParagraphs[t.currentChapter.paragraphIndex];if(!n)throw new Error("Unable to locate the current Word chapter heading.");mo(n,"PlotDirector Chapter",`PD-CHAPTER-${en}`,"PD-CHAPTER"),await e.sync()}),Qt=en,rn=!1,nn="ChapterID Anchor",tn="Chapter anchor",$r(e),ir(e),Zr({lastError:"-"}),lr(),!0}catch(e){return console.error("Unable to attach PlotDirector chapter ID.",e),$r("Unable to attach PlotDirector chapter ID."),Zr({lastError:ea(e)}),lr(),!1}},fo=async e=>{Wr(),await jo(),ir(e),$r(e)},go=e=>{ln&&(ln(e),ln=null),ct?.close?ct.close():ct&&(ct.hidden=!0)},So=()=>{if(!nt)return;const e=Fr(tt?.value||"").toLocaleLowerCase(),t=sn.filter(t=>!e||String(t.title||"").toLocaleLowerCase().includes(e));if(nt.innerHTML="",dn=null,rt&&(rt.disabled=!0),0===t.length){const e=document.createElement("p");return e.className="word-companion-empty-list",e.textContent="No chapters found.",void nt.append(e)}for(const e of t){const t=Number.parseInt(e.chapterId||"",10);if(!Number.isInteger(t)||t<=0)continue;const n=document.createElement("label");n.className="word-companion-scene-option";const r=document.createElement("input");r.type="radio",r.name="word-companion-link-chapter",r.value=String(t),r.addEventListener("change",()=>{dn=t,rt&&(rt.disabled=!1)});const a=document.createElement("span");a.textContent=e.title||"Untitled chapter",n.append(r,a),nt.append(n)}},Io=()=>{et?.close?et.close():et&&(et.hidden=!0)},Co=async(e,t,n)=>{const r=sa();if(!r)return Ar("Select a PlotDirector book first."),!1;await Qr(r.bookId,e,t,"Manual link","Title Match");return!!await yo(n)&&(Ar(n),Ur(),!0)},bo=e=>{cn&&(cn(e),cn=null),ze?.close?ze.close():ze&&(ze.hidden=!0)},ko=()=>{if(!Ve)return;const e=Fr(Fe?.value||"").toLocaleLowerCase(),t=an.filter(t=>!e||String(t.title||"").toLocaleLowerCase().includes(e));if(Ve.innerHTML="",on=null,Je&&(Je.disabled=!0),0===t.length){const e=document.createElement("p");return e.className="word-companion-empty-list",e.textContent="No scenes found.",void Ve.append(e)}for(const e of t){const t=Number.parseInt(e.sceneId||"",10);if(!Number.isInteger(t)||t<=0)continue;const n=document.createElement("label");n.className="word-companion-scene-option";const r=document.createElement("input");r.type="radio",r.name="word-companion-link-scene",r.value=String(t),r.addEventListener("change",()=>{on=t,Je&&(Je.disabled=!1)});const a=document.createElement("span");a.textContent=e.title||"Untitled scene",n.append(r,a),Ve.append(n)}},vo=()=>{Ge?.close?Ge.close():Ge&&(Ge.hidden=!0)},xo=()=>{Rn=!1,Cr(),Un&&(Un=!1,No(1e3))},Eo=async(e={})=>{const t=e.source||"manual";if(!Zt)return void mr("No resolved PlotDirector scene.");if(!en)return void mr("No resolved PlotDirector chapter.");if(Ln)return void mr("Refresh Current Scene before syncing.");const n=sa(),r=Ia();if(!n||!r)return void mr("Bound manuscript metadata is unavailable.");if(Rn)return Un=!0,void er("Scene sync deferred; sync already running.");pr(),Rn=!0,Un=!1;let a=zt;try{a=await za()}catch(e){return mr("Sync failed"),Zr({lastError:ea(e)}),er("Scene sync failed."),void xo()}if(!Number.isInteger(a)||a<0)return mr("Sync failed"),er("Scene sync failed."),void xo();if(Mn===Zt&&On===a)return mr("Synced"),er("Sync skipped (count unchanged)."),void xo();er("Scene word count changed."),ge&&(ge.disabled=!0,ge.textContent="Syncing..."),mr("Syncing..."),er(`Scene sync started (${t}).`);try{const e=await io("/api/word-companion/runtime/scene-word-count",{documentGuid:r,bookId:n.bookId,chapterId:en,sceneId:Zt,wordCount:a}),t=e?.actualWords??a,o=new Date;Mn=Zt,On=t,Xr(Ie,Er(t)),Xr(he,Er(t)),Xr(Ce,Nr(o)),Xr(fe,Nr(o)),mr("Synced"),er("Scene sync succeeded.")}catch(e){mr("Sync failed"),Zr({lastError:ea(e)}),er("Scene sync failed.")}finally{ge&&(ge.textContent="Sync Current Scene"),xo()}},No=(e=4e3)=>{pr(),Zt&&en&&!Ln&&!Rn&&(Wn=window.setTimeout(()=>{Wn=null,Eo({source:"automatic"})},e))},Lo=()=>{Hn&&(window.clearTimeout(Hn),Hn=null)},Po=()=>{Fn=null,Vn="",Jn=[],Yn=null,_n="",Lo()},qo=async(e=!1)=>{const t=ia(),n=Ia();if(!t||!n)return Jn=[],[];if(!e&&Fn===t.projectId&&Vn===n&&Jn.length>0)return Jn;const r=await co(`/api/word-companion/runtime/characters?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(n)}`);return Fn=t.projectId,Vn=n,Jn=Array.isArray(r?.characters)?r.characters:[],er("Character alias cache refreshed."),Jn},Do=(e,t)=>{const n=String(t||"").trim();if(!n)return!1;const r=(a=n,String(a||"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).replace(/\s+/g,"\\s+");var a;return new RegExp(`(^|[^\\p{L}\\p{N}_])${r}(?=$|[^\\p{L}\\p{N}_])`,"iu").test(e)},Ao=async()=>{if(Hn=null,Zt&&!Ln&&Ia()){if(Bn)return Gn=!0,void er("Character suggestion detection deferred; detection already running.");Bn=!0,Gn=!1;try{const[e,t]=await Promise.all([Ka(),qo()]),n=((e,t)=>{if(!e||!Array.isArray(t)||0===t.length)return[];const n=new Map;for(const r of t){const t=Number.parseInt(r.characterId||"",10);!Number.isInteger(t)||t<=0||n.has(t)||Do(e,r.matchText)&&n.set(t,r.name||r.matchText||"Character")}return[...n.entries()].map(([e,t])=>({characterId:e,name:t}))})(e,t),r=n.map(e=>e.characterId),a=r.slice().sort((e,t)=>e-t).join(",");if(!a||Yn===Zt&&_n===a)return void er("Character suggestions skipped.");const o=await io("/api/word-companion/runtime/character-suggestions",{documentGuid:Ia(),sceneId:Zt,characterIds:r});if(Yn=Zt,_n=a,(o?.createdCount||0)>0){const e=n.slice(0,3).map(e=>e.name).join(", "),t=n.length>3?" +"+(n.length-3):"";ir(e?`Characters detected: ${e}${t}`:o.message)}er(o?.message||"Character suggestions submitted.")}catch(e){console.error("Unable to detect character suggestions.",e),Zr({lastError:ea(e)})}finally{Bn=!1,Gn&&(Gn=!1,$o(1500))}}},$o=(e=2500)=>{Lo(),!Zt||Ln||Bn?Bn&&(Gn=!0):Hn=window.setTimeout(()=>{Ao()},e)},To=async()=>{const e=ia(),t=sa(),n=Vr(Yt,"chapter");if(Jr({projectId:e?.projectId,projectTitle:e?.title,bookId:t?.bookId,bookTitle:t?ca(t):void 0,detectedChapter:Yt,detectedScene:_t,requestChapter:n,requestScene:"",result:"Not run",chapterId:null,sceneId:null}),!t)return Or("Not detected"),ir("Select a PlotDirector book first."),!1;if(!Yt)return Or("Not detected"),ir("No chapter detected in Word. Use Heading 1 for chapters."),!1;Or("Not detected");try{const e=await _r(t.bookId),r=Qt?e.find(e=>e.chapterId===Qt):null,a=n.toLocaleLowerCase(),o=a?e.find(e=>Vr(e.title,"chapter").toLocaleLowerCase()===a):null,c=r||o;return c?(Wr(),vr(null,c.chapterId,r?"Chapter anchor":"Chapter title"),nn=r?"ChapterID Anchor":"Title Match",sr("Chapter linked to PlotDirector"),ir("No scene detected in Word. Use Heading 2 for scenes."),Jr({result:"Chapter matched",chapterId:c.chapterId,sceneId:null}),!0):(vr(null),sr("Chapter not found in PlotDirector."),ir("Chapter not found in PlotDirector."),Jr({result:"Chapter not matched",chapterId:null,sceneId:null}),Rr("Chapter not found in PlotDirector."),!1)}catch(e){return Or("Not found in PlotDirector"),Zr({lastError:ea(e)}),ir("Unable to load PlotDirector chapter data."),!1}},jo=async()=>{const e=ia(),t=sa(),n=Vr(Yt,"chapter"),r=Vr(_t,"scene");if(Jr({projectId:e?.projectId,projectTitle:e?.title,bookId:t?.bookId,bookTitle:t?ca(t):void 0,detectedChapter:Yt,detectedScene:_t,requestChapter:n,requestScene:r,result:"Not run",chapterId:null,sceneId:null}),dr({anchorType:Xt?"SceneID Anchor":Qt?"ChapterID Anchor":"Title Match",storedSceneId:Xt,storedChapterId:Qt,resolutionMethod:"-"}),!t)return Or("Not detected"),ir("Select a PlotDirector book first."),Jr({result:"Error"}),!1;if(!Yt||!_t)return Or("Not detected"),ir("No scene detected in Word. Use Heading 2 for scenes."),Jr({result:"Error"}),!1;ne&&(ne.disabled=!0,ne.textContent="Refreshing...");const a=()=>{ne&&(ne.disabled=!1,ne.textContent="Refresh PlotDirector Scene")};Or("Not detected"),ir("Resolving PlotDirector scene...");try{if(Xt){const e=await(async(e,t)=>{const n=await co(`/api/word-companion/books/${e}/structure`),r=Array.isArray(n?.chapters)?n.chapters:[];for(const e of r){const n=Array.isArray(e.scenes)?e.scenes:[];for(const r of n)if(t(e,r))return{chapter:e,scene:r}}return null})(t.bookId,(e,t)=>t.sceneId===Xt);if(e)return Jr({result:"Matched",chapterId:e.chapter.chapterId,sceneId:e.scene.sceneId}),await Qr(t.bookId,e.scene.sceneId,e.chapter.chapterId,"Anchor","SceneID Anchor"),!0;rn=!0,nn="SceneID Anchor",sr("Not found in PlotDirector"),ir("Stored PlotDirector ID is invalid."),Jr({result:"Error",chapterId:Qt,sceneId:Xt}),dr({anchorType:"SceneID Anchor",storedSceneId:Xt,storedChapterId:Qt,resolutionMethod:"Anchor"})}if(Qt){const e=(await Yr(t.bookId)).find(e=>e.chapterId===Qt),n=e?(Array.isArray(e.scenes)?e.scenes:[]).find(e=>Vr(e.title,"scene").toLocaleLowerCase()===r.toLocaleLowerCase()):null;if(n)return Jr({result:"Matched",chapterId:e.chapterId,sceneId:n.sceneId}),await Qr(t.bookId,n.sceneId,e.chapterId,"Anchor","ChapterID Anchor"),!0;e&&!Xt?(nn="ChapterID Anchor",vr(null,Qt,"Chapter anchor"),Jr({result:"Chapter matched",chapterId:Qt,sceneId:null})):Xt||(nn="ChapterID Anchor",Jr({result:"Chapter anchor not found",chapterId:Qt,sceneId:null}))}const e=await io(`/api/word-companion/books/${t.bookId}/resolve-scene`,{chapterTitle:n,sceneTitle:r});if(!e?.matched||!e.sceneId){const t=rn,n=Number.parseInt(e?.chapterId||"",10),r=Number.isInteger(en)&&en>0?en:null,o=Number.isInteger(n)&&n>0?n:r,c=!!e?.chapterMatched||!!o;return Or("Not found in PlotDirector"),rn=t,c&&(vr(null,o,o===r?"Chapter anchor":"Chapter title"),sr("Scene not found in PlotDirector.")),ir(t?"Stored PlotDirector ID is invalid.":c?"Scene not found in PlotDirector.":"This chapter does not exist in PlotDirector. Create or link the chapter first."),Jr({result:"Not matched",chapterId:c?o:e?.chapterId,sceneId:e?.sceneId}),t||(c?(Wr(),Mr("Scene not found in PlotDirector.")):(Ur(),Rr("Chapter not found in PlotDirector."))),a(),!1}const o=rn;return Jr({result:o?"Matched by title fallback":"Matched",chapterId:e.chapterId,sceneId:e.sceneId}),await Qr(t.bookId,e.sceneId,e.chapterId,o?"Title fallback":"Title","Title Match"),o&&(rn=!0,ir("Stored PlotDirector ID is invalid."),lr()),!0}catch(e){const t=rn;return Zr({lastError:ea(e)}),Or("Not found in PlotDirector"),rn=t,ir(t?"Stored PlotDirector ID is invalid.":"Unable to load PlotDirector scene data."),Jr({result:"Error"}),!1}finally{a()}},Wo=async()=>{if(Pn=null,jn)return An=!0,void er("Runtime update deferred; update already running.");if(!Ot||!sa())return qn=!1,void er("Runtime update skipped.");if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return qn=!1,br("Manual"),void ir("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");if(!mn)return qn=!1,br("Manual"),void ir("Document structure is not cached yet. Use Refresh Current Scene.");const e=Date.now()-Dn;if(qn&&e<$n)return er("Runtime update skipped (typing active)."),void Ro($n-e);jn=!0,qn=!1,An=!1,br("Updating..."),er("Runtime update executed.");try{const e=await window.Word.run(async e=>await(async e=>{const t=e.document.getSelection().paragraphs;return t.load("text,styleBuiltIn,style"),await e.sync(),t.items})(e)),t=$a(mn,e),n=Ta(t);if(await za(),!n)return kr(!1),br("Current scene updated"),No(),void $o();_t?await jo():await To(),kr(!1),br("Current scene updated"),ir("Current scene updated."),No(),$o()}catch(e){console.error("Unable to refresh current scene from Word selection.",e),Zr({lastError:ea(e)}),kr(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving.")}finally{jn=!1,(An||qn)&&(An=!1,Ro($n))}},Ro=(e=1200)=>{Pn&&window.clearTimeout(Pn),Pn=window.setTimeout(Wo,Math.max(0,e)),br("Waiting for typing to pause"),er("Runtime update scheduled.")},Uo=()=>{((e="selection",t=1200)=>{if(qn=!0,Dn=Date.now(),pr(),Lo(),er(`${e} changed.`),jn)return An=!0,void br("Waiting for typing to pause");Ro(t)})("Selection")},Mo=()=>{if(Tn&&window.Office?.context?.document&&"function"==typeof window.Office.context.document.removeHandlerAsync&&window.Office?.EventType?.DocumentSelectionChanged)try{window.Office.context.document.removeHandlerAsync(window.Office.EventType.DocumentSelectionChanged,{handler:Uo}),Tn=!1}catch(e){console.warn("Unable to remove Word selection tracking handler.",e)}},Oo=async(e,n)=>{if(mn=null,qr(),!e)return Bt=[],aa(O,"Select a project first"),aa(m,"Select a project first"),cr(""),ra(t,null),Ca(),Or("Not detected"),void wr();aa(O,"Loading books..."),cr(""),Or("Not detected"),wr("Select a book to analyse manuscript structure.");try{const r=await co(`/api/word-companion/projects/${e}/books`);if(Bt=Array.isArray(r.books)?r.books:[],0===Bt.length)return aa(O,"No books available."),aa(m,"No books available."),cr("No books available."),ra(t,null),Ca(),void ya("No books available.");oa(O,"Choose a book",Bt.map(e=>({...e,displayTitle:ca(e)})),"bookId","displayTitle");const a=Bt.find(e=>e.bookId===n);a&&O?(O.value=String(a.bookId),ra(t,a.bookId)):ra(t,null),((e=null)=>{if(!m)return;if(0===Bt.length)return void aa(m,"No books available.");oa(m,"Choose a book",Bt.map(e=>({...e,displayTitle:ca(e)})),"bookId","displayTitle");const t=e||Number.parseInt(O?.value||"",10),n=Bt.find(e=>e.bookId===t);n&&(m.value=String(n.bookId)),pa()})(a?.bookId||n),Ca(),Or((sa(),"Not detected")),wr(sa()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure."),ya(la()?"Ready to scan manuscript structure.":"Select a Book to begin.")}catch{Bt=[],aa(O,"Unable to load books."),aa(m,"Unable to load books."),cr("Unable to load books."),ra(t,null),Ca(),Or("Not detected"),wr("Unable to load books."),ya("Unable to load books.")}};for(const e of l)e.addEventListener("click",()=>nr(e.dataset.tabButton));rr(),M?.addEventListener("change",async()=>{const n=Number.parseInt(M.value||"",10);Pr(),h&&Number.isInteger(n)&&n>0&&(h.value=String(n)),ra(e,Number.isInteger(n)&&n>0?n:null),ra(t,null),Or("Not detected"),wr(),ya("Select a Book to begin."),await Oo(n,null)}),O?.addEventListener("change",()=>{const e=Number.parseInt(O.value||"",10);Pr(),ra(t,Number.isInteger(e)&&e>0?e:null),m&&Number.isInteger(e)&&e>0&&(m.value=String(e)),Ca(),Or("Not detected"),wr(sa()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure."),ya(la()?"Ready to scan manuscript structure.":"Select a Book to begin.")}),h?.addEventListener("change",async()=>{const n=Number.parseInt(h.value||"",10);Pr(),M&&Number.isInteger(n)&&n>0&&(M.value=String(n)),ra(e,Number.isInteger(n)&&n>0?n:null),ra(t,null),ya("Select a Book to begin."),await Oo(n,null)}),m?.addEventListener("change",()=>{const e=Number.parseInt(m.value||"",10);Pr(),O&&Number.isInteger(e)&&e>0&&(O.value=String(e)),ra(t,Number.isInteger(e)&&e>0?e:null),Ca(),ya(la()?"Ready to scan manuscript structure.":"Select a Book to begin.")}),y?.addEventListener("input",pa),w?.addEventListener("click",async()=>{const e=da(),t=String(y?.value||"").trim();if(e&&t){w.disabled=!0,ua("Creating Book...");try{const n=await io(`/api/word-companion/projects/${e.projectId}/books`,{title:t});y&&(y.value=""),M&&(M.value=String(e.projectId)),await Oo(e.projectId,n.bookId),m&&(m.value=String(n.bookId)),ua("Ready to scan manuscript structure.")}catch(e){console.error("Unable to create Book from Word Companion.",e),ua(`Unable to create Book: ${ea(e)}`)}finally{pa()}}else pa()}),f?.addEventListener("click",async()=>{const e=da(),t=la();if(e&&t)if(Gt&&Ft&&window.Word&&"function"==typeof window.Word.run){f&&(f.disabled=!0,f.textContent="Scanning..."),ua("Scanning manuscript structure...");try{const n=await window.Word.run(async e=>{const n=e.document.body.paragraphs;return n.load("text,styleBuiltIn,style"),await e.sync(),((e,t)=>{const n=[];let r=null,a=null,o=0;const c=[],i=new Set(["***","###"]),s=()=>{if(!r)return null;const e={title:`Scene ${r.scenes.length+1}`,sortOrder:10*(r.scenes.length+1),wordCount:0};return r.scenes.push(e),e};return e.forEach(e=>{const d=String(e.text||"").trim();if(!d)return;if(c.push(d),ka(e,1))return r={title:d,sortOrder:10*(n.length+1),wordCount:0,scenes:[]},n.push(r),a=s(),void(o+=va(d));if(!r||!a)return;if(t&&i.has(d))return void(a=s());const l=va(d);r.wordCount+=l,a.wordCount+=l,o+=l}),{chapters:n,chapterCount:n.length,sceneCount:n.reduce((e,t)=>e+t.scenes.length,0),wordCount:o,documentText:c.join("\n")}})(n.items,!!t.usesExplicitScenes)});gn=n,In=!1;const r=await io("/api/word-companion/manuscript/analyse",{projectId:e.projectId,bookId:t.bookId,documentGuid:Sa(),chapterCount:n.chapterCount,sceneCount:n.sceneCount,wordCount:n.wordCount});fn=r,(e=>{if(!I)return;I.innerHTML="";const t=document.createElement("strong");t.textContent="Manuscript Analysis",I.append(t);const n=document.createElement("dl"),r=[["Project",e.projectTitle],["Book",ca({title:e.bookTitle,subtitle:e.bookSubtitle})],["Chapters",Number(e.chapterCount||0).toLocaleString()],["Scenes",Number(e.sceneCount||0).toLocaleString()],["Words",Number(e.wordCount||0).toLocaleString()]];for(const[e,t]of r){const r=document.createElement("dt");r.textContent=e;const a=document.createElement("dd");a.textContent=t||"-",n.append(r,a)}I.append(n),hr(I,!1),hr(L,!1),ua(e.message||"Preview generated."),pa()})(r);try{const t=await io("/api/word-companion/manuscript/discover-characters",{projectId:e.projectId,documentText:n.documentText||""});Sn=Array.isArray(t?.candidates)?t.candidates:[],hr(C,!0),hr(v,!0)}catch(e){console.error("Unable to discover character candidates.",e),Sn=[],hr(C,!0),hr(v,!0)}Zr({lastScan:"Success",lastError:"-",paragraphs:"-",heading1:String(n.chapterCount),heading2:"-"})}catch(e){console.error("Unable to scan manuscript for first-run import.",e),ya(`Unable to scan manuscript: ${ea(e)}`),Zr({lastScan:"Failure",lastError:ea(e)})}finally{f&&(f.textContent="Scan Manuscript"),pa()}}else ya("Word document access is unavailable.");else ya("Select a Project and Book to begin.")}),P?.addEventListener("click",async()=>{const n=da(),i=la();if(!(n&&i&&gn&&fn?.canImport))return void pa();let s=!1;if(!fn.requiresReplaceConfirmation||(s=await new Promise(e=>{if(!D||"function"!=typeof D.showModal)return void e(window.confirm("This Book already contains planned chapters and scenes.\n\nImporting this manuscript will replace the planned structure.\n\nContinue?"));const t=t=>{A?.removeEventListener("click",n),$?.removeEventListener("click",r),D?.removeEventListener("cancel",a),D?.close(),e(t)},n=()=>t(!0),r=()=>t(!1),a=e=>{e.preventDefault(),t(!1)};A?.addEventListener("click",n),$?.addEventListener("click",r),D?.addEventListener("cancel",a),D.showModal()}),s)){kn=!0,pa(),ua("Importing manuscript structure...");try{const l=Sa(),u=await io("/api/word-companion/manuscript/import",{projectId:n.projectId,bookId:i.bookId,documentGuid:l,bindingVersion:1,replacePlanned:s,chapters:gn.chapters});if(!u.imported)return fn={...fn,canImport:!u.requiresReplaceConfirmation,requiresReplaceConfirmation:!!u.requiresReplaceConfirmation,message:u.message||fn.message},ua(u.message||"Import was not completed."),void pa();const p=u.manuscriptDocument;await(d={documentGuid:p?.documentGuid||l,bookId:u.bookId,projectId:u.projectId,bindingVersion:p?.bindingVersion||1},new Promise((e,t)=>{const n=window.Office?.context?.document?.settings;n?(n.set(r,d.documentGuid),n.set(a,String(d.bookId)),n.set(o,String(d.projectId)),n.set(c,String(d.bindingVersion||1)),n.saveAsync(n=>{n.status===window.Office.AsyncResultStatus.Succeeded?e():t(n.error||new Error("Unable to save Word document metadata."))})):t(new Error("Word document settings are unavailable."))})),pn={documentGuid:p?.documentGuid||l,bookId:u.bookId,projectId:u.projectId,bindingVersion:p?.bindingVersion||1},ra(e,u.projectId),ra(t,u.bookId),M&&(M.value=String(u.projectId));const h=Sn;await Oo(u.projectId,u.bookId),ar("Connected"),In=!0,Cn=h.length>0,bn=Cn?Date.now():0,Sn=h,h.length>0?(ha(!0),fa(h),hr(L,!0),hr(v,!1),ua(u.message||"Manuscript structure imported."),ir(u.message||"Manuscript structure imported."),window.setTimeout(pa,750)):await so(u.message||"Manuscript structure imported.")}catch(e){console.error("Unable to import manuscript structure.",e),ua(`Unable to import manuscript: ${ea(e)}`)}finally{kn=!1,pa()}var d}else ua("Import cancelled.")}),x?.addEventListener("click",async()=>{const e=da()||ia(),t=wa();if(!Cn||Date.now()-bn<750||!e||0===t.length)pa();else{vn=!0,pa(),Xr(b,"Creating selected characters...");try{const n=await io("/api/word-companion/manuscript/create-discovered-characters",{projectId:e.projectId,candidateNames:t});ir(n.message||"Characters created."),Xr(b,`${n.createdCount||0} created, ${n.skippedCount||0} already existed.`),await so(n.message||"Characters created.")}catch(e){console.error("Unable to create discovered characters.",e),Xr(b,`Unable to create characters: ${ea(e)}`)}finally{vn=!1,pa()}}}),E?.addEventListener("click",()=>so("Character creation skipped.")),N?.addEventListener("click",()=>so()),g?.addEventListener("click",()=>ha(!1)),q?.addEventListener("click",()=>ya("Import cancelled.")),F?.addEventListener("click",Qa),X?.addEventListener("click",Xa),Z?.addEventListener("click",async()=>{const e=sa();if(!e||0===fr().length||xn)return void gr();if(!await eo())return;xn=!0,Sr(),yr("Applying structure sync...");const t={createdChapters:0,createdScenes:0,linkedChapters:0,linkedScenes:0,skipped:Array.isArray(un?.manualReview)?un.manualReview.length:0,failed:0},n=fr().filter(e=>"couldLink"===e.category&&"Chapter"===e.type),r=fr().filter(e=>"wouldCreateChapters"===e.category),a=fr().filter(e=>"couldLink"===e.category&&"Scene"===e.type),o=fr().filter(e=>"wouldCreateScenes"===e.category),c=[];let i="";const s=(e,t)=>{c.push({item:e,counterName:t})},d=async(e,n)=>{try{await(async e=>{if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)throw new Error("Word document access is unavailable.");await window.Word.run(async t=>{const n=await Ya(t),r="Chapter"===e.type?e.wordChapter:e.wordScene,a=Number.isInteger(r?.paragraphIndex)?n.bodyParagraphs[r.paragraphIndex]:null;if(!a)throw new Error("Unable to locate the Word heading.");if("Chapter"===e.type){const t=e.pdChapter?.chapterId;if(!t)throw new Error("Chapter ID is not available.");mo(a,"PlotDirector Chapter",`PD-CHAPTER-${t}`,"PD-CHAPTER")}else{const t=e.pdScene?.sceneId;if(!t)throw new Error("Scene ID is not available.");mo(a,"PlotDirector Scene",`PD-SCENE-${t}`,"PD-SCENE")}await t.sync()})})(e),to(e,"Success"),t[n]+=1}catch(n){to(e,"Failed",ea(n)),t.failed+=1}};try{for(const e of n)s(e,"linkedChapters");for(const n of r)try{await ao(e.bookId,n),s(n,"createdChapters")}catch(e){to(n,"Failed",ea(e)),t.failed+=1}for(const e of a)s(e,"linkedScenes");for(const n of o)try{await oo(e.bookId,n),s(n,"createdScenes")}catch(e){to(n,"Failed",ea(e)),t.failed+=1}for(const e of c)await d(e.item,e.counterName);for(const e of un.manualReview||[])to(e,"Skipped");Ja(un),i=(e=>`Structure Sync Complete. Created: ${e.createdChapters} Chapters, ${e.createdScenes} Scenes. Linked: ${e.linkedChapters} Chapters, ${e.linkedScenes} Scenes. Skipped: ${e.skipped} Manual Review items. Failed: ${e.failed} Items.`)(t),yr(i)}finally{xn=!1,Sr(),i&&(qr(),await Xa(),yr(`${i} Preview refreshed.`))}}),ht?.addEventListener("click",()=>Za(!0)),mt?.addEventListener("click",()=>Za(!1)),ut?.addEventListener("cancel",e=>{e.preventDefault(),Za(!1)}),ne?.addEventListener("click",jo),G?.addEventListener("click",async()=>{if(!sa())return ir("Select a PlotDirector book first."),void Or("Not detected");Pn&&(window.clearTimeout(Pn),Pn=null),qn=!1,An=!1,xr(!0),br("Updating...");try{await qo(!0);if(!await Qa())return;if(kr(!1),!_t)return await To(),void br("Current scene updated");await jo(),br("Current scene updated")}finally{xr(!1)}}),ge?.addEventListener("click",()=>Eo({source:"manual"})),Pe?.addEventListener("click",async()=>{if(Zt)if(!Ln&&await(async()=>{if(!Zt)return!1;if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return kr(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1;try{const e=await window.Word.run(async e=>await Ya(e)),t=e.currentChapter?.title||"",n=e.currentScene?.title||"",r=e.currentScene?.anchorId||null,a=e.currentChapter?.anchorId||null,o=Number.isInteger(r)&&r===Zt,c=Number.isInteger(a)&&a===en,i=Vr(n,"scene").toLocaleLowerCase()===Vr(Kn||_t,"scene").toLocaleLowerCase(),s=Vr(t,"chapter").toLocaleLowerCase()===Vr(Qn||Yt,"chapter").toLocaleLowerCase();return o||i&&(c||s)?(kr(!1),!0):(kr(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1)}catch(e){return console.error("Unable to verify current Word scene before saving.",e),Zr({lastError:ea(e)}),kr(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1}})()){Pe&&(Pe.disabled=!0,Pe.textContent="Saving...");try{await(e=`/api/word-companion/scenes/${Zt}/links`,t={characterIds:po(Ee),assetIds:po(Ne),locationIds:[],primaryLocationId:ho()},co(e,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})),(()=>{const e=new Set(po(Ee)),t=new Set(po(Ne));Zn={characters:Zn.characters.map(t=>({...t,linked:e.has(Number.parseInt(Hr(t,"character"),10))})),assets:Zn.assets.map(e=>({...e,linked:t.has(Number.parseInt(Hr(e,"asset"),10))})),locations:Zn.locations,primaryLocationId:ho()}})(),Dr("Scene links saved successfully."),Zr({lastError:"-"})}catch(e){Dr("Unable to save scene links."),Zr({lastError:ea(e)})}finally{Pe&&(Pe.disabled=!Zt||Ln,Pe.textContent="Save Scene Links")}var e,t}else Dr("The Word cursor is now in a different scene. Refresh Current Scene before saving.");else Dr("Link a PlotDirector scene first.")}),se?.addEventListener("click",async()=>{await yo()}),Te?.addEventListener("click",async()=>{const e=sa();if(!e||!Yt||en)return void Rr("Chapter not found in PlotDirector.");const t=Fr(Yt),n=await((e,t)=>(Xr(it,`"${e}"`),Xr(st,`"${t}"`),ct?new Promise(e=>{ln=e,ct.showModal?ct.showModal():ct.hidden=!1}):Promise.resolve(window.confirm(`Create PlotDirector chapter:\n\n"${e}"\n\nin book:\n\n"${t}"\n\n?`))))(t,ca(e)||"selected book");if(n){Te&&(Te.disabled=!0,Te.textContent="Creating...");try{const n=Number.isInteger(Kt)&&Kt>0?10*Kt:null,r=await io(`/api/word-companion/books/${e.bookId}/chapters`,{title:t,sortOrder:n});if(!r?.chapterId)throw new Error("Chapter creation did not return a chapter ID.");qr(),vr(null,r.chapterId,"Manual chapter link");if(!await wo("Chapter created and linked successfully."))return;await fo("Chapter created and linked successfully.")}catch(e){$r("Unable to create chapter."),Zr({lastError:ea(e)})}finally{Te&&(Te.disabled=!Tr(),Te.textContent="Create Chapter in PlotDirector")}}}),je?.addEventListener("click",async()=>{const e=sa();if(e&&Yt&&!en){je&&(je.disabled=!0,je.textContent="Loading...");try{sn=await _r(e.bookId),dn=null,tt&&(tt.value=""),Xr(ot,""),So(),et?.showModal?et.showModal():et&&(et.hidden=!1)}catch(e){$r("Unable to load chapters."),Zr({lastError:ea(e)})}finally{je&&(je.disabled=!Tr(),je.textContent="Link to Existing Chapter")}}else Rr("Chapter not found in PlotDirector.")}),tt?.addEventListener("input",So),rt?.addEventListener("click",async()=>{const e=sn.find(e=>e.chapterId===dn);if(e){rt&&(rt.disabled=!0,rt.textContent="Linking...");try{vr(null,e.chapterId,"Manual chapter link");if(!await wo("Chapter linked successfully."))return;Io(),await fo("Chapter linked successfully.")}catch(e){Xr(ot,"Unable to link chapter."),$r("Unable to link chapter."),Zr({lastError:ea(e)})}finally{rt&&(rt.disabled=!dn,rt.textContent="Link Chapter")}}else Xr(ot,"Select a chapter.")}),at?.addEventListener("click",Io),dt?.addEventListener("click",()=>go(!0)),lt?.addEventListener("click",()=>go(!1)),ct?.addEventListener("cancel",e=>{e.preventDefault(),go(!1)}),Oe?.addEventListener("click",async()=>{const e=sa();if(!e||!_t)return void Mr("Scene not found in PlotDirector.");const t=Vr(_t,"scene"),n=Vr(Yt,"chapter"),r=await((e,t)=>(Xr(Ke,`"${e}"`),Xr(Qe,`"${t}"`),ze?new Promise(e=>{cn=e,ze.showModal?ze.showModal():ze.hidden=!1}):Promise.resolve(window.confirm(`Create PlotDirector scene:\n\n"${e}"\n\nwithin chapter:\n\n"${t}"\n\n?`))))(t,n);if(r){Oe&&(Oe.disabled=!0,Oe.textContent="Creating...");try{const n=await Kr();if(!n)return void Mr("This chapter does not exist in PlotDirector. Create or link the chapter first.");const r=await io(`/api/word-companion/books/${e.bookId}/chapters/${n.chapterId}/scenes`,{sceneTitle:t});if(!r?.sceneId||!r?.chapterId)throw new Error("Scene creation did not return a scene ID.");qr(),await Co(r.sceneId,r.chapterId,"Scene created and linked successfully.")}catch(e){Ar("Unable to create scene."),Zr({lastError:ea(e)})}finally{Oe&&(Oe.disabled=!jr(),Oe.textContent="Create Scene in PlotDirector")}}}),He?.addEventListener("click",async()=>{const e=sa();if(e&&_t){He&&(He.disabled=!0,He.textContent="Loading...");try{const t=await Yr(e.bookId),n=zr(t);if(!n)return void Mr("This chapter does not exist in PlotDirector. Create or link the chapter first.");an=Array.isArray(n.scenes)?n.scenes:[],on=null,Fe&&(Fe.value=""),Xr(_e,""),ko(),Ge?.showModal?Ge.showModal():Ge&&(Ge.hidden=!1)}catch(e){Ar("Unable to load scenes."),Zr({lastError:ea(e)})}finally{He&&(He.disabled=!jr(),He.textContent="Link to Existing Scene")}}else Mr("Scene not found in PlotDirector.")}),Fe?.addEventListener("input",ko),Je?.addEventListener("click",async()=>{const e=sa(),t=an.find(e=>e.sceneId===on);if(e&&t){Je&&(Je.disabled=!0,Je.textContent="Linking...");try{const e=await Kr();if(!e)throw new Error("This chapter does not exist in PlotDirector. Create or link the chapter first.");vo(),await Co(t.sceneId,e.chapterId,"Scene linked successfully.")}catch(e){Xr(_e,"Unable to link scene."),Ar("Unable to link scene."),Zr({lastError:ea(e)})}finally{Je&&(Je.disabled=!on,Je.textContent="Link Scene")}}else Xr(_e,"Select a scene.")}),Ye?.addEventListener("click",vo),Xe?.addEventListener("click",()=>bo(!0)),Ze?.addEventListener("click",()=>bo(!1)),ze?.addEventListener("cancel",e=>{e.preventDefault(),bo(!1)}),Et?.addEventListener("click",async()=>{Et&&(Et.disabled=!0,Et.textContent="Running...");try{if(await ta(),!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return void Zr({lastScan:"Failure",lastError:"Word document access is unavailable.",paragraphs:"-",heading1:"-",heading2:"-"});const e=await window.Word.run(async e=>{const t=e.document.body.paragraphs;return t.load("items"),await e.sync(),t.items.length});Zr({lastScan:"Success",lastError:"-",paragraphs:String(e)})}catch(e){console.error("Word Companion diagnostics failed.",e);const t=ea(e);Zr({lastScan:"Failure",lastError:t}),ir(`Unable to scan the Word document: ${t}`)}finally{Et&&(Et.disabled=!1,Et.textContent="Run Diagnostics")}});const Ho=Ot?(async()=>{aa(M,"Loading projects..."),aa(O,"Select a project first"),aa(h,"Loading projects..."),aa(m,"Select a project first"),or(""),cr("");try{const n=await co("/api/word-companion/projects");if(Ht=Array.isArray(n.projects)?n.projects:[],0===Ht.length)return aa(M,"No projects available."),aa(h,"No projects available."),or("No projects available."),ra(e,null),ra(t,null),Ca(),void ya("No projects available.");oa(M,"Choose a project",Ht,"projectId","title"),ma();const r=na(e),a=Ht.find(e=>e.projectId===r);a&&M?(M.value=String(a.projectId),h&&(h.value=String(a.projectId)),ra(e,a.projectId),await Oo(a.projectId,na(t))):(ra(e,null),ra(t,null),Ca(),ya("Select a Project and Book to begin."))}catch{Ht=[],Bt=[],aa(M,"Unable to connect to PlotDirector."),aa(O,"Select a project first"),aa(h,"Unable to connect to PlotDirector."),aa(m,"Select a project first"),ar("Unable to connect to PlotDirector."),or("Unable to connect to PlotDirector."),ra(e,null),ra(t,null),Ca(),ya("Unable to connect to PlotDirector.")}})():Promise.resolve();if(Ot||(aa(M,"Please sign in to PlotDirector."),aa(O,"Please sign in to PlotDirector."),aa(h,"Please sign in to PlotDirector."),aa(m,"Please sign in to PlotDirector."),Ca()),!window.Office||"function"!=typeof window.Office.onReady)return tr("Word Companion ready"),ir("Word document access is unavailable."),br("Manual"),void Zr({host:"Unavailable",platform:"Unavailable",ready:"No",wordApi:"No"});ta().then(async()=>{tr("Word Companion ready"),await Ho,await(async()=>{if(!Ot||!Ft)return void ha(!1);const n=ga();if(n)try{const r=await co(`/api/word-companion/runtime/book/${n.bookId}?documentGuid=${encodeURIComponent(n.documentGuid)}`),a=r?.manuscriptDocument;if(r?.bookId===n.bookId&&r?.projectId===n.projectId&&a&&String(a.documentGuid).toLowerCase()===n.documentGuid.toLowerCase())return pn=n,Lr(r),ra(e,r.projectId),ra(t,r.bookId),M&&(M.value=String(r.projectId)),await Oo(r.projectId,r.bookId),ha(!1),ar("Connected"),cr("Bound manuscript detected."),void await uo()}catch{}pn=null,Pr(),ma(),da()?await Oo(da().projectId,null):aa(m,"Select a project first"),ya("Select a Project and Book to begin."),ha(!0)})(),Ft?(()=>{if(Ot){if(!window.Office?.context?.document||"function"!=typeof window.Office.context.document.addHandlerAsync||!window.Office?.EventType?.DocumentSelectionChanged)return br("Manual"),void ir("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");try{window.Office.context.document.addHandlerAsync(window.Office.EventType.DocumentSelectionChanged,Uo,e=>{e?.status===window.Office.AsyncResultStatus.Succeeded?(Tn=!0,br("Live")):(br("Manual"),ir("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene."))}),window.addEventListener("beforeunload",Mo)}catch(e){console.warn("Unable to register Word selection tracking handler.",e),br("Manual"),ir("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.")}}})():(ir("Word document access is unavailable."),br("Manual"))}).catch(e=>{console.error("Office readiness check failed.",e),ar("Unable to connect to PlotDirector."),tr("Word Companion unavailable"),ir("Word document access is unavailable."),Zr({ready:"No",wordApi:"No",lastScan:"Failure"})})})(); \ No newline at end of file +(()=>{const e="plotdirector.word.projectId",t="plotdirector.word.bookId",n="plotdirector.word.activeTab",r="plotdirector.word.documentGuid",a="plotdirector.word.boundBookId",o="plotdirector.word.boundProjectId",c="plotdirector.word.bindingVersion",i=new Set(["scene","links","structure","diagnostics"]),s=document.querySelector(".word-companion-shell"),d=document.querySelector(".word-companion-tabs"),l=[...document.querySelectorAll("[data-tab-button]")],u=[...document.querySelectorAll("[data-tab-panel]")],p=document.querySelector("[data-first-run-wizard]"),h=document.querySelector("[data-first-run-project-select]"),m=document.querySelector("[data-first-run-book-select]"),y=document.querySelector("[data-first-run-new-book-title]"),w=document.querySelector("[data-first-run-create-book]"),f=document.querySelector("[data-first-run-scan]"),g=document.querySelector("[data-first-run-cancel]"),S=document.querySelector("[data-first-run-status]"),I=document.querySelector("[data-first-run-summary]"),C=document.querySelector("[data-first-run-character-section]"),b=document.querySelector("[data-first-run-character-status]"),k=document.querySelector("[data-first-run-character-candidates]"),v=document.querySelector("[data-first-run-character-actions]"),x=document.querySelector("[data-first-run-create-characters]"),N=document.querySelector("[data-first-run-skip-characters]"),E=document.querySelector("[data-first-run-continue]"),L=document.querySelector("[data-first-run-import-actions]"),P=document.querySelector("[data-first-run-import]"),q=document.querySelector("[data-first-run-import-cancel]"),D=document.querySelector("[data-first-run-replace-dialog]"),A=document.querySelector("[data-first-run-replace-confirm]"),$=document.querySelector("[data-first-run-replace-cancel]"),T=document.querySelector("[data-office-status]"),j=document.querySelector("[data-connection-status]"),R=document.querySelector("[data-summary-connection]"),W=document.querySelector("[data-summary-project]"),U=document.querySelector("[data-summary-book]"),M=document.querySelector("[data-project-select]"),O=document.querySelector("[data-book-select]"),H=document.querySelector("[data-project-message]"),B=document.querySelector("[data-book-message]"),G=document.querySelector("[data-refresh-current-scene]"),F=document.querySelector("[data-refresh-document]"),V=document.querySelector("[data-current-chapter]"),J=document.querySelector("[data-current-scene]"),Y=document.querySelector("[data-current-word-count]"),_=document.querySelector("[data-scene-tracking-status]"),z=document.querySelector("[data-document-message]"),K=document.querySelector("[data-sync-note]"),Q=document.querySelector("[data-document-outline]"),X=document.querySelector("[data-analyse-manuscript-structure]"),Z=document.querySelector("[data-apply-structure-sync]"),ee=document.querySelector("[data-structure-preview-status]"),te=document.querySelector("[data-structure-preview-results]"),ne=document.querySelector("[data-refresh-plotdirector-scene]"),re=document.querySelector("[data-plotdirector-scene-status]"),ae=document.querySelector("[data-anchor-status]"),oe=document.querySelector("[data-anchor-book-id]"),ce=document.querySelector("[data-anchor-chapter-id]"),ie=document.querySelector("[data-anchor-scene-id]"),se=document.querySelector("[data-attach-plotdirector-ids]"),de=document.querySelector("[data-plotdirector-scene-details]"),le=document.querySelector("[data-plotdirector-scene-title]"),ue=document.querySelector("[data-plotdirector-revision-status]"),pe=document.querySelector("[data-plotdirector-estimated-words]"),he=document.querySelector("[data-plotdirector-actual-words]"),me=document.querySelector("[data-plotdirector-blocked-status]"),ye=document.querySelector("[data-plotdirector-blocked-reason-row]"),we=document.querySelector("[data-plotdirector-blocked-reason]"),fe=document.querySelector("[data-runtime-last-sync]"),ge=document.querySelector("[data-sync-scene-progress]"),Se=document.querySelector("[data-sync-word-count]"),Ie=document.querySelector("[data-sync-plotdirector-count]"),Ce=document.querySelector("[data-sync-last-synced]"),be=document.querySelector("[data-sync-status]"),ke=document.querySelector("[data-writing-brief-block]"),ve=document.querySelector("[data-writing-brief]"),xe=document.querySelector("[data-plotdirector-link-groups]"),Ne=document.querySelector("[data-character-chips]"),Ee=document.querySelector("[data-asset-chips]"),Le=(document.querySelector("[data-location-chips]"),document.querySelector("[data-primary-location-select]")),Pe=document.querySelector("[data-save-scene-links]"),qe=document.querySelector("[data-scene-links-status]"),De=document.querySelector("[data-links-editing-scene]"),Ae=document.querySelector("[data-chapter-create-link]"),$e=document.querySelector("[data-chapter-create-link-chapter]"),Te=document.querySelector("[data-create-plotdirector-chapter]"),je=document.querySelector("[data-link-existing-chapter]"),Re=document.querySelector("[data-chapter-create-link-status]"),We=document.querySelector("[data-scene-create-link]"),Ue=document.querySelector("[data-create-link-chapter]"),Me=document.querySelector("[data-create-link-scene]"),Oe=document.querySelector("[data-create-plotdirector-scene]"),He=document.querySelector("[data-link-existing-scene]"),Be=document.querySelector("[data-create-link-status]"),Ge=document.querySelector("[data-link-existing-dialog]"),Fe=document.querySelector("[data-link-scene-search]"),Ve=document.querySelector("[data-link-scene-options]"),Je=document.querySelector("[data-link-selected-scene]"),Ye=document.querySelector("[data-link-dialog-cancel]"),_e=document.querySelector("[data-link-dialog-status]"),ze=document.querySelector("[data-create-scene-dialog]"),Ke=document.querySelector("[data-create-dialog-scene]"),Qe=document.querySelector("[data-create-dialog-chapter]"),Xe=document.querySelector("[data-create-dialog-confirm]"),Ze=document.querySelector("[data-create-dialog-cancel]"),et=document.querySelector("[data-link-existing-chapter-dialog]"),tt=document.querySelector("[data-link-chapter-search]"),nt=document.querySelector("[data-link-chapter-options]"),rt=document.querySelector("[data-link-selected-chapter]"),at=document.querySelector("[data-link-chapter-dialog-cancel]"),ot=document.querySelector("[data-link-chapter-dialog-status]"),ct=document.querySelector("[data-create-chapter-dialog]"),it=document.querySelector("[data-create-chapter-dialog-chapter]"),st=document.querySelector("[data-create-chapter-dialog-book]"),dt=document.querySelector("[data-create-chapter-dialog-confirm]"),lt=document.querySelector("[data-create-chapter-dialog-cancel]"),ut=document.querySelector("[data-apply-structure-sync-dialog]"),pt=document.querySelector("[data-apply-structure-sync-summary]"),ht=document.querySelector("[data-apply-structure-sync-confirm]"),mt=document.querySelector("[data-apply-structure-sync-cancel]"),yt=document.querySelector("[data-resolve-project-id]"),wt=document.querySelector("[data-resolve-project-title]"),ft=document.querySelector("[data-resolve-book-id]"),gt=document.querySelector("[data-resolve-book-title]"),St=document.querySelector("[data-resolve-detected-chapter]"),It=document.querySelector("[data-resolve-detected-scene]"),Ct=document.querySelector("[data-resolve-request-chapter]"),bt=document.querySelector("[data-resolve-request-scene]"),kt=document.querySelector("[data-resolve-result]"),vt=document.querySelector("[data-resolve-chapter-id]"),xt=document.querySelector("[data-resolve-scene-id]"),Nt=document.querySelector("[data-run-diagnostics]"),Et=document.querySelector("[data-diagnostic-host]"),Lt=document.querySelector("[data-diagnostic-platform]"),Pt=document.querySelector("[data-diagnostic-ready]"),qt=document.querySelector("[data-diagnostic-word-api]"),Dt=document.querySelector("[data-diagnostic-last-scan]"),At=document.querySelector("[data-diagnostic-last-error]"),$t=document.querySelector("[data-diagnostic-anchor-type]"),Tt=document.querySelector("[data-diagnostic-stored-scene-id]"),jt=document.querySelector("[data-diagnostic-stored-chapter-id]"),Rt=document.querySelector("[data-diagnostic-resolution-method]"),Wt=document.querySelector("[data-diagnostic-paragraphs]"),Ut=document.querySelector("[data-diagnostic-heading1]"),Mt=document.querySelector("[data-diagnostic-heading2]"),Ot="true"===s?.dataset.authenticated;let Ht=[],Bt=[],Gt=!1,Ft=!1,Vt="Unknown",Jt="Unknown",Yt="",_t="",zt=null,Kt=null,Qt=null,Xt=null,Zt=null,en=null,tn="",nn="Title Match",rn=!1,an=[],on=null,cn=null,sn=[],dn=null,ln=null,un=null,pn=null,hn=null,mn=null,yn=null,wn=null,fn=null,gn=null,Sn=[],In=!1,Cn=!1,bn=0,kn=!1,vn=!1,xn=!1,Nn=null,En="Manual",Ln=!1,Pn=null,qn=!1,Dn=0,An=!1;const $n=1200;let Tn=!1,jn=!1,Rn=null,Wn=!1,Un=!1,Mn=null,On=null,Hn=null,Bn=!1,Gn=!1,Fn=null,Vn="",Jn=[],Yn=null,_n="",zn=null,Kn="",Qn=[],Xn=null,Zn="",er="",tr="",nr="",rr=0,ar={characters:[],assets:[],locations:[],primaryLocationId:null};const or=e=>{const t=Date.now();t-rr<1e3||(rr=t,console.debug(`[Word Companion Runtime] ${e}`))},cr=e=>{T&&(T.textContent=e)},ir=(e,t=!0)=>{const r=i.has(e)&&l.some(t=>t.dataset.tabButton===e)?e:"scene";for(const e of l){const t=e.dataset.tabButton===r;e.classList.toggle("is-active",t),e.setAttribute("aria-selected",t?"true":"false")}for(const e of u){const t=e.dataset.tabPanel===r;e.classList.toggle("is-active",t),e.hidden=!t}t&&((e,t)=>{try{t?window.localStorage.setItem(e,String(t)):window.localStorage.removeItem(e)}catch{}})(n,r)},sr=()=>{const e=(e=>{try{return window.localStorage.getItem(e)||""}catch{return""}})(n);ir(i.has(e)?e:"scene",!1)},dr=e=>{j&&(j.textContent=e),R&&(R.textContent=e)},lr=e=>{H&&(H.textContent=e)},ur=e=>{B&&(B.textContent=e)},pr=e=>{z&&(z.textContent=e)},hr=e=>{re&&(re.textContent=e)},mr=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("anchorType")&&ra($t,Dr(e.anchorType)),t("storedSceneId")&&ra(Tt,Dr(e.storedSceneId)),t("storedChapterId")&&ra(jt,Dr(e.storedChapterId)),t("resolutionMethod")&&ra(Rt,Dr(e.resolutionMethod))},yr=()=>{const e=ha(),t=Number.isInteger(Zt)&&Zt>0&&Xt===Zt,n=!Number.isInteger(en)||en<=0||Qt===en,r=t&&n;ra(ae,r?"Attached to PlotDirector":"Not attached"),ra(oe,e?.bookId?String(e.bookId):"-"),ra(ce,Number.isInteger(en)&&en>0?String(en):"-"),ra(ie,Number.isInteger(Zt)&&Zt>0?String(Zt):"-"),se&&(se.disabled=!Zt||r&&!rn,se.textContent=Xt&&!r?"Reattach PlotDirector IDs":"Attach PlotDirector IDs"),mr({anchorType:nn||"Title Match",storedSceneId:Xt,storedChapterId:Qt,resolutionMethod:tn})},wr=(e,t,n,r=null,a=null,o=null)=>{const c=e||"",i=t||"",s=Number.isInteger(n)?n:null,d=Number.isInteger(o)&&o>0?o:null,l=Number.isInteger(r)&&r>0?r:null,u=Number.isInteger(a)&&a>0?a:null,p=Yt===c&&_t===i&&zt===s&&Kt===d&&Qt===l&&Xt===u;Yt=e||"",_t=t||"",zt=Number.isInteger(n)?n:null,Kt=Number.isInteger(o)&&o>0?o:null,Qt=Number.isInteger(r)&&r>0?r:null,Xt=Number.isInteger(a)&&a>0?a:null,p||(V&&(V.textContent=e||"Not detected"),J&&(J.textContent=t||"Not detected"),Y&&(Y.textContent=Number.isInteger(n)?String(n):"-"),ra(Se,Number.isInteger(n)?String(n):"-"),yr())},fr=()=>{Rn&&(window.clearTimeout(Rn),Rn=null)},gr=(e,t)=>{e&&(e.hidden=t)},Sr=e=>{ra(be,e)},Ir=e=>{ra(ee,e)},Cr=(e="Select a project and book to analyse manuscript structure.")=>{if(un=null,te){te.innerHTML="";const e=document.createElement("p");e.textContent="No preview generated.",te.append(e)}Ir(e),kr()},br=(e=un)=>((e=un)=>Ha.flatMap(t=>Array.isArray(e?.[t.key])?e[t.key]:[]))(e).filter(e=>"couldLink"===e.category||"wouldCreateChapters"===e.category||"wouldCreateScenes"===e.category),kr=()=>{Z&&(Z.disabled=xn||0===br().length)},vr=()=>{X&&(X.disabled=xn||!pa()||!ha()),kr()},xr=()=>{De&&(De.textContent=Zt?`Editing links for: ${tr||_t||"Current scene"}`:"Link a PlotDirector scene first.")},Nr=()=>{const e=Ln||!Zt,t=e||!en||Wn;ge&&(ge.disabled=t),Pe&&(Pe.disabled=e),Le&&(Le.disabled=e);for(const t of[Ne,Ee])for(const n of t?[...t.querySelectorAll("input[type='checkbox']")]:[])n.disabled=e},Er=e=>{"Live"!==e&&"Manual"!==e||(En=e),ra(_,e||En||"Manual")},Lr=(e,t="")=>{Ln=!!e,Ln&&(fr(),$o()),ra(_,Ln?"Stale":En),Nr(),t&&(pr(t),Rr(t))},Pr=(e,t=null,n="")=>{Zt=Number.isInteger(e)&&e>0?e:null,en=Number.isInteger(t)&&t>0?t:null,tn=n||"",Zt!==Mn&&(On=null),Zt||(fr(),$o()),Nr(),Sr(Ln?"Refresh Current Scene before syncing.":Zt?"Ready to sync.":"No resolved PlotDirector scene."),Rr(Ln?"Refresh Current Scene before saving.":Zt?"Ready to save.":"Link a PlotDirector scene first."),xr(),yr()},qr=e=>{G&&(G.disabled=e,G.textContent=e?"Refreshing...":"Refresh Current Scene")},Dr=e=>null==e||""===e?"-":String(e),Ar=e=>{if(!e)return"-";const t=e instanceof Date?e:new Date(e);if(Number.isNaN(t.getTime()))return"-";const n=new Date;return`Last synced: ${t.toDateString()===n.toDateString()?"Today":t.toLocaleDateString()} ${t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}`},$r=e=>{hn=e||null;const t=hn?.lastSyncUtc||hn?.manuscriptDocument?.lastSyncUtc;ra(fe,Ar(t)),ra(Ce,Ar(t))},Tr=()=>{mn=null,yn=null,wn=null,To(),jo(),$r(null)},jr=()=>{yn=null,wn=null},Rr=e=>{ra(qe,e)},Wr=e=>{ra(Be,e)},Ur=e=>{ra(Re,e)},Mr=()=>!!ha()&&!!Yt&&!en,Or=()=>!!ha()&&!!_t&&Number.isInteger(en)&&en>0,Hr=()=>{gr(Ae,!0),Ur(""),Te&&(Te.disabled=!0,Te.textContent="Create Chapter in PlotDirector"),je&&(je.disabled=!0,je.textContent="Link to Existing Chapter")},Br=(e="")=>{ra($e,Dr(Yt)),gr(Ae,!1),Ur(e);const t=Mr();Te&&(Te.disabled=!t,Te.textContent="Create Chapter in PlotDirector"),je&&(je.disabled=!t,je.textContent="Link to Existing Chapter")},Gr=()=>{gr(We,!0),Wr(""),Oe&&(Oe.disabled=!0,Oe.textContent="Create Scene in PlotDirector"),He&&(He.disabled=!0,He.textContent="Link to Existing Scene")},Fr=(e="")=>{ra(Ue,Dr(Yt)),ra(Me,Dr(_t)),gr(We,!1),Wr(e);const t=Or();Oe&&(Oe.disabled=!t,Oe.textContent="Create Scene in PlotDirector"),He&&(He.disabled=!t,He.textContent="Link to Existing Scene")},Vr=e=>{hr(e),gr(de,!0),gr(ke,!0),gr(xe,!1),Hr(),Gr(),tn="",tr="",nr="",nn=Xt?"SceneID Anchor":Qt?"ChapterID Anchor":"Title Match",rn=!1,ar={characters:[],assets:[],locations:[],primaryLocationId:null},Yr(Ne,[],"character"),Yr(Ee,[],"asset"),_r([],null,!1),Pr(null),ra(Ie,"-"),ra(le,"-"),ra(ue,"-"),ra(pe,"-"),ra(he,"-"),ra(me,"-"),ra(we,"-"),gr(ye,!0),yr(),xr()},Jr=(e,t)=>"asset"===t?e?.assetId||e?.AssetId||e?.storyAssetId||e?.StoryAssetId||0:"location"===t?e?.locationId||e?.LocationId||0:e?.characterId||e?.CharacterId||0,Yr=(e,t,n,r=!1)=>{if(!e)return;e.innerHTML="";const a=Array.isArray(t)?t:[];if(0===a.length){const t=document.createElement("p");return t.className="word-companion-empty-list",t.textContent="None",void e.append(t)}for(const t of a){const a=Number.parseInt(Jr(t,n),10);if(!Number.isInteger(a)||a<=0)continue;const o=document.createElement("label");o.className="word-companion-check-item";const c=document.createElement("input");c.type="checkbox",c.value=String(a),c.checked=!!t.linked,c.disabled=!r;const i=document.createElement("span");i.textContent=t.name||"Unnamed",o.append(c,i),e.append(o)}},_r=(e,t,n=!1)=>{if(!Le)return;Le.innerHTML="";const r=document.createElement("option");r.value="",r.textContent="None",Le.append(r);const a=Number.parseInt(t||"",10);for(const t of Array.isArray(e)?e:[]){const e=Number.parseInt(Jr(t,"location"),10);if(!Number.isInteger(e)||e<=0)continue;const n=document.createElement("option");n.value=String(e),n.textContent=t.name||"Unnamed",n.selected=e===a,Le.append(n)}Le.disabled=!n},zr=e=>String(e||"").trim().replace(/\s+/g," "),Kr=(e,t)=>{const n=zr(e);if(!n)return"";const r=new RegExp(`^${"scene"===t?"scene":"chapter"}\\s+(?:\\d+|[ivxlcdm]+|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)\\s*(?::|-|\\u2013|\\u2014)\\s*`,"i");return zr(n.replace(r,""))||n},Qr=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("projectId")&&ra(yt,Dr(e.projectId)),t("projectTitle")&&ra(wt,Dr(e.projectTitle)),t("bookId")&&ra(ft,Dr(e.bookId)),t("bookTitle")&&ra(gt,Dr(e.bookTitle)),t("detectedChapter")&&ra(St,Dr(e.detectedChapter)),t("detectedScene")&&ra(It,Dr(e.detectedScene)),t("requestChapter")&&ra(Ct,Dr(e.requestChapter)),t("requestScene")&&ra(bt,Dr(e.requestScene)),t("result")&&ra(kt,Dr(e.result)),t("chapterId")&&ra(vt,Dr(e.chapterId)),t("sceneId")&&ra(xt,Dr(e.sceneId))},Xr=async e=>{if(wn===e&&Array.isArray(yn?.chapters))return yn.chapters;const t=await po(`/api/word-companion/books/${e}/structure`);return wn=e,yn=t||null,Array.isArray(t?.chapters)?t.chapters:[]},Zr=async e=>{const t=await po(`/api/word-companion/books/${e}/chapters`);return Array.isArray(t?.chapters)?t.chapters:[]},ea=e=>{if(Number.isInteger(en)&&en>0){const t=e.find(e=>e.chapterId===en);if(t)return t}const t=Kr(Yt,"chapter").toLocaleLowerCase();return t&&e.find(e=>Kr(e.title,"chapter").toLocaleLowerCase()===t)||null},ta=async()=>{const e=ha();return e?ea(await Xr(e.bookId)):null},na=async(e,t,n,r,a)=>{const o=await po(`/api/word-companion/scenes/${t}/companion`);try{o.revisionStatus=await(async(e,t)=>{const n=await po(`/api/word-companion/books/${e}/structure`),r=Array.isArray(n?.chapters)?n.chapters:[];for(const e of r){const n=(Array.isArray(e.scenes)?e.scenes:[]).find(e=>e.sceneId===t);if(n)return n.revisionStatus||""}return""})(e,t)}catch{o.revisionStatus=""}var c;nn=a||"Title Match",rn=!1,Lr(!1),hr("Linked to PlotDirector"),pr(""),Hr(),Gr(),Pr(t,n,r),c=o,tr=c?.sceneTitle||_t||"",nr=c?.chapterTitle||Yt||"",ra(le,Dr(c?.sceneTitle)),ra(ue,Dr(c?.revisionStatus||c?.revisionStatusName||"Not provided")),ra(pe,Dr(c?.estimatedWords)),ra(he,Dr(c?.actualWords)),ra(Ie,Dr(c?.actualWords)),ra(me,c?.blocked?"Blocked":"Not blocked"),c?.blockedReason?(ra(we,c.blockedReason),gr(ye,!1)):(ra(we,"-"),gr(ye,!0)),ve&&(ve.textContent=c?.writingBrief||"No writing brief has been added for this scene."),ar={characters:Array.isArray(c?.characters)?c.characters:[],assets:Array.isArray(c?.assets)?c.assets:[],locations:Array.isArray(c?.locations)?c.locations:[],primaryLocationId:c?.primaryLocationId??null},Yr(Ne,ar.characters,"character",!!Zt&&!Ln),Yr(Ee,ar.assets,"asset",!!Zt&&!Ln),_r(ar.locations,ar.primaryLocationId,!!Zt&&!Ln),xr(),Rr(Ln?"Refresh Current Scene before saving.":Zt?"Ready to save.":"No resolved PlotDirector scene."),gr(de,!1),gr(ke,!1),gr(xe,!1),yo(t,n),Ao(),Oo()},ra=(e,t)=>{if(e){const n=null==t?"":String(t);e.textContent!==n&&(e.textContent=n)}},aa=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("host")&&ra(Et,e.host),t("platform")&&ra(Lt,e.platform),t("ready")&&ra(Pt,e.ready),t("wordApi")&&ra(qt,e.wordApi),t("lastScan")&&ra(Dt,e.lastScan),t("lastError")&&ra(At,e.lastError),t("paragraphs")&&ra(Wt,e.paragraphs),t("heading1")&&ra(Ut,e.heading1),t("heading2")&&ra(Mt,e.heading2)},oa=e=>{const t=[];return e?.name&&t.push(e.name),e?.code&&e.code!==e.name&&t.push(e.code),e?.message&&t.push(e.message),e?.debugInfo?.errorLocation&&t.push(`Location: ${e.debugInfo.errorLocation}`),t.length>0?t.join(": "):String(e)},ca=async()=>{if(!window.Office||"function"!=typeof window.Office.onReady)return Gt=!1,Ft=!1,Vt="Unavailable",Jt="Unavailable",aa({host:Vt,platform:Jt,ready:"No",wordApi:"No"}),null;const e=await window.Office.onReady();return Gt=!0,Vt=e?.host||"Unknown",Jt=e?.platform||"Unknown",Ft=!!window.Word&&!!window.Office.HostType&&e?.host===window.Office.HostType.Word,aa({host:Vt,platform:Jt,ready:"Yes",wordApi:Ft?"Yes":"No"}),e},ia=e=>{try{const t=window.localStorage.getItem(e),n=Number.parseInt(t||"",10);return Number.isInteger(n)&&n>0?n:null}catch{return null}},sa=(e,t)=>{try{t?window.localStorage.setItem(e,String(t)):window.localStorage.removeItem(e)}catch{}},da=(e,t)=>{if(!e)return;e.innerHTML="";const n=document.createElement("option");n.value="",n.textContent=t,e.append(n),e.disabled=!0},la=(e,t,n,r,a)=>{if(!e)return;e.innerHTML="";const o=document.createElement("option");o.value="",o.textContent=t,e.append(o);for(const t of n){const n=document.createElement("option");n.value=String(t[r]),n.textContent=t[a],e.append(n)}e.disabled=0===n.length},ua=e=>{const t=String(e?.title||"").trim(),n=String(e?.subtitle||"").trim();return n?`${t}: ${n}`:t},pa=()=>{const e=Number.parseInt(M?.value||"",10);return Ht.find(t=>t.projectId===e)||null},ha=()=>{const e=Number.parseInt(O?.value||"",10);return Bt.find(t=>t.bookId===e)||null},ma=()=>{const e=Number.parseInt(h?.value||"",10);return Ht.find(t=>t.projectId===e)||null},ya=()=>{const e=Number.parseInt(m?.value||"",10);return Bt.find(t=>t.bookId===e)||null},wa=e=>ra(S,e),fa=()=>{const e=ma(),t=ya(),n=Cn&&Date.now()-bn>=750;f&&(f.disabled=!e||!t||kn),w&&(w.disabled=!e||!String(y?.value||"").trim()||kn),P&&(P.disabled=!fn?.canImport||!gn||kn),x&&(x.disabled=!n||vn||0===Ca().length)},ga=e=>{gr(p,!e),gr(d,e);for(const t of u)gr(t,!!e||"scene"!==t.dataset.tabPanel&&!t.classList.contains("is-active"));e||sr()},Sa=()=>{if(!h)return;if(0===Ht.length)return void da(h,"No projects available.");la(h,"Choose a project",Ht,"projectId","title");const e=Number.parseInt(M?.value||"",10);Number.isInteger(e)&&e>0&&(h.value=String(e))},Ia=(e="Select a Project and Book to begin.")=>{fn=null,gn=null,Sn=[],In=!1,Cn=!1,bn=0,gr(I,!0),gr(L,!0),gr(C,!0),gr(v,!0),I&&(I.innerHTML=""),k&&(k.innerHTML=""),ra(b,""),wa(e),fa()},Ca=()=>k?[...k.querySelectorAll("input[type='checkbox']:checked")].map(e=>String(e.value||"").trim()).filter(Boolean):[],ba=e=>{if(Sn=Array.isArray(e)?e:[],C&&k){if(k.innerHTML="",gr(C,!1),gr(v,!In||0===Sn.length),gr(x,!1),gr(N,!1),gr(E,!0),0===Sn.length)return ra(b,"No likely major characters found."),void fa();ra(b,`${Sn.length} likely major characters found.`);for(const e of Sn){const t=document.createElement("label");t.className="word-companion-character-candidate";const n=document.createElement("input");n.type="checkbox",n.value=e.text||"",n.checked="high"===String(e.confidence||"").trim().toLowerCase(),n.addEventListener("change",fa);const r=document.createElement("strong");r.textContent=e.text||"";const a=document.createElement("em"),o=String(e.reason||"").trim();a.textContent=o?`${Number(e.mentionCount||0).toLocaleString()} mentions · ${o}`:`${Number(e.mentionCount||0).toLocaleString()} mentions`;const c=document.createElement("span");c.className="word-companion-character-candidate-text",c.append(r,a),t.append(n,c),k.append(t)}fa()}},ka=()=>{const e=window.Office?.context?.document?.settings;if(!e)return null;const t=String(e.get(r)||"").trim(),n=Number.parseInt(e.get(a)||"",10),i=Number.parseInt(e.get(o)||"",10),s=Number.parseInt(e.get(c)||"",10);return!t||!Number.isInteger(n)||n<=0||!Number.isInteger(i)||i<=0?null:{documentGuid:t,bookId:n,projectId:i,bindingVersion:Number.isInteger(s)&&s>0?s:1}},va=()=>pn?.documentGuid?pn.documentGuid:window.crypto?.randomUUID?window.crypto.randomUUID():"10000000-1000-4000-8000-100000000000".replace(/[018]/g,e=>(Number(e)^16*Math.random()>>Number(e)/4).toString(16)),xa=()=>pn?.documentGuid||ka()?.documentGuid||"",Na=()=>{const e=pa(),t=ha();W&&(W.textContent=e?.title||"(Not connected)"),U&&(U.textContent=t?ua(t):"(Not connected)"),K&&(K.textContent=t?"":"Select a PlotDirector book before refreshing."),vr()},Ea=e=>String(e?.styleBuiltIn||e?.style||"").replace(/\s+/g,"").toLowerCase(),La=(e,t)=>{const n=Ea(e);return n===`heading${t}`||n.endsWith(`.heading${t}`)||n.includes(`heading${t}`)},Pa=e=>String(e||"").trim().split(/\s+/).filter(Boolean).length,qa=(e,t)=>{const n=String(e||"").match(new RegExp(`^${t}-(\\d+)$`,"i"));if(!n)return null;const r=Number.parseInt(n[1],10);return Number.isInteger(r)&&r>0?r:null},Da=e=>{try{return Array.isArray(e?.contentControls?.items)?e.contentControls.items:[]}catch(e){return console.warn("Word paragraph content controls were not available.",e),[]}},Aa=(e,t)=>{const n=Da(e);for(const e of n){const n=qa(e.tag,t);if(n)return n}return null},$a=(e,t)=>{const n=[];let r=0,a=0,o=null,c=null;e.forEach((e,t)=>{const i=String(e.text||"").trim();if(i){if(La(e,1))return r+=1,o={index:n.length+1,paragraphIndex:t,title:i,anchorId:Aa(e,"PD-CHAPTER"),scenes:[]},n.push(o),void(c=null);if(La(e,2)){if(a+=1,!o)return;return c={index:o.scenes.length+1,paragraphIndex:t,title:i,anchorId:Aa(e,"PD-SCENE"),wordCount:0},void o.scenes.push(c)}c&&(c.wordCount+=Pa(i))}});const i=t.find(e=>String(e.text||"").trim()),s=i?e.findIndex(e=>{return t=e,n=i,String(t?.text||"").trim()===String(n?.text||"").trim()&&Ea(t)===Ea(n);var t,n}):-1,d=s>=0&&n.filter(e=>e.paragraphIndex<=s).at(-1)||null,l=d&&s>=0&&d.scenes.filter(e=>e.paragraphIndex<=s).at(-1)||null;return{chapters:n,currentChapter:d,currentScene:l,paragraphCount:e.length,heading1Count:r,heading2Count:a}},Ta=new Set(["***","###"]),ja=(e,t)=>{const n=String(e?.text||"").trim();return{index:t,text:n,styleBuiltIn:e?.styleBuiltIn||"",style:e?.style||"",wordCount:Pa(n),chapterAnchorId:null,sceneAnchorId:null}},Ra=(e,t)=>{e&&(e.endParagraphIndex=t)},Wa=(e,t)=>{e&&(e.endParagraphIndex=t,Ra(e.scenes.at(-1),t))},Ua=(e,t)=>{const n=(t||[]).find(e=>String(e.text||"").trim());if(!e||!n)return e?.currentParagraphIndex??-1;const r=e.paragraphs.filter(e=>((e,t)=>String(e?.text||"").trim()===String(t?.text||"").trim()&&Ea(e)===Ea(t))(e,n)).map(e=>e.index);return 0===r.length?e.currentParagraphIndex??-1:Number.isInteger(e.currentParagraphIndex)?r.reduce((t,n)=>Math.abs(n-e.currentParagraphIndex){if(!mn)return!1;const t=((e,t)=>!e||!Number.isInteger(t)||t<0?null:e.chapters.filter(e=>e.startParagraphIndex<=t).at(-1)||null)(mn,e),n=((e,t)=>!e||!Number.isInteger(t)||t<0?null:e.scenes.filter(e=>e.startParagraphIndex<=t).at(-1)||null)(t,e),r=t?.startParagraphIndex!==mn.currentChapter?.startParagraphIndex||n?.startParagraphIndex!==mn.currentScene?.startParagraphIndex||t?.anchorId!==mn.currentChapter?.anchorId||n?.anchorId!==mn.currentScene?.anchorId;return mn.currentParagraphIndex=e,mn.currentChapter=t,mn.currentScene=n,!!r&&(wr(t?.title,n?.title,n?.wordCount,t?.anchorId,n?.anchorId,t?.index),r)},Oa=e=>{if(!Q)return;if(Q.innerHTML="",0===e.chapters.length){const e=document.createElement("p");return e.textContent="No chapters detected. Use Heading 1 for chapter titles.",void Q.append(e)}if(!e.chapters.some(e=>e.scenes.length>0)){const e=document.createElement("p");e.textContent="No scenes detected. Use Heading 2 for scene titles.",Q.append(e)}for(const t of e.chapters){const e=document.createElement("div");e.className="word-companion-outline-chapter";const n=document.createElement("strong");if(n.textContent=t.title,e.append(n),t.scenes.length>0){const n=document.createElement("ul");for(const e of t.scenes){const t=document.createElement("li");t.textContent=e.title,n.append(t)}e.append(n)}Q.append(e)}},Ha=[{key:"alreadyLinked",title:"Already Linked"},{key:"couldLink",title:"Could Link"},{key:"wouldCreateChapters",title:"Would Create Chapters"},{key:"wouldCreateScenes",title:"Would Create Scenes"},{key:"manualReview",title:"Manual Review Required"}],Ba={alreadyLinked:"Already Linked",couldLink:"Could Link",wouldCreateChapter:"Would Create Chapter",wouldCreateScene:"Would Create Scene",manualReview:"Manual Review Required"},Ga={alreadyLinked:"✓",couldLink:"~",wouldCreateChapter:"+",wouldCreateScene:"+",manualReview:"?"},Fa=(e,t)=>Kr(e,t).toLocaleLowerCase(),Va=({category:e,action:t,type:n,wordTitle:r,match:a="",anchorStatus:o="None",matches:c=[],pdChapter:i=null,pdScene:s=null,wordChapter:d=null,wordScene:l=null,parentItem:u=null})=>({id:`${n}-${d?.index||0}-${l?.index||0}-${d?.paragraphIndex??l?.paragraphIndex??0}`,category:e,action:t,type:n,wordTitle:r,match:a,anchorStatus:o,matches:c,pdChapter:i,pdScene:s,wordChapter:d,wordScene:l,parentItem:u,result:"Pending",error:""}),Ja=(e,t)=>{Array.isArray(e[t.category])&&e[t.category].push(t)},Ya=e=>Array.isArray(e?.scenes)?e.scenes:[],_a=(e,t,n)=>{const r=e.anchorId?`PD-CHAPTER-${e.anchorId}`:"None";if(e.anchorId){const a=t.find(t=>t.chapterId===e.anchorId);if(a){const t=Va({category:"alreadyLinked",action:"alreadyLinked",type:"Chapter",wordTitle:e.title,match:`Chapter ${a.chapterId}: ${a.title}`,anchorStatus:r,pdChapter:a,wordChapter:e});return Ja(n,t),t}const o=Va({category:"manualReview",action:"manualReview",type:"Chapter",wordTitle:e.title,anchorStatus:`${r} not found`,matches:[],pdChapter:null,wordChapter:e});return Ja(n,o),o}const a=t.filter(t=>Fa(t.title,"chapter")===Fa(e.title,"chapter"));if(1===a.length){const t=Va({category:"couldLink",action:"couldLink",type:"Chapter",wordTitle:e.title,match:`Chapter ${a[0].chapterId}: ${a[0].title}`,anchorStatus:r,pdChapter:a[0],wordChapter:e});return Ja(n,t),t}if(a.length>1){const t=Va({category:"manualReview",action:"manualReview",type:"Chapter",wordTitle:e.title,anchorStatus:r,matches:a.map(e=>`Chapter ${e.chapterId}: ${e.title}`),pdChapter:null,wordChapter:e});return Ja(n,t),t}const o=Va({category:"wouldCreateChapters",action:"wouldCreateChapter",type:"Chapter",wordTitle:e.title,anchorStatus:r,pdChapter:null,wordChapter:e});return Ja(n,o),o},za=(e,t,n,r)=>{const a=e.anchorId?`PD-SCENE-${e.anchorId}`:"None";if(e.anchorId){const o=((e,t)=>{for(const n of e){const e=Ya(n).find(e=>e.sceneId===t);if(e)return{chapter:n,scene:e}}return null})(n,e.anchorId);return o?void Ja(r,Va({category:"alreadyLinked",action:"alreadyLinked",type:"Scene",wordTitle:e.title,match:`Scene ${o.scene.sceneId}: ${o.scene.title}`,anchorStatus:a,pdChapter:o.chapter,pdScene:o.scene,wordChapter:t?.wordChapter,wordScene:e,parentItem:t})):void Ja(r,Va({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:e.title,anchorStatus:`${a} not found`,wordChapter:t?.wordChapter,wordScene:e,parentItem:t}))}if(!t?.pdChapter&&"manualReview"===t?.category)return void Ja(r,Va({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:e.title,anchorStatus:a,matches:["Parent chapter requires manual review."],wordChapter:t?.wordChapter,wordScene:e,parentItem:t}));if(!t?.pdChapter)return void Ja(r,Va({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:e.title,anchorStatus:a,wordChapter:t?.wordChapter,wordScene:e,parentItem:t}));const o=Ya(t.pdChapter).filter(t=>Fa(t.title,"scene")===Fa(e.title,"scene"));1!==o.length?o.length>1?Ja(r,Va({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:e.title,anchorStatus:a,matches:o.map(e=>`Scene ${e.sceneId}: ${e.title}`),wordChapter:t.wordChapter,wordScene:e,parentItem:t})):Ja(r,Va({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:e.title,anchorStatus:a,pdChapter:t.pdChapter,wordChapter:t.wordChapter,wordScene:e,parentItem:t})):Ja(r,Va({category:"couldLink",action:"couldLink",type:"Scene",wordTitle:e.title,match:`Scene ${o[0].sceneId}: ${o[0].title}`,anchorStatus:a,pdChapter:t.pdChapter,pdScene:o[0],wordChapter:t.wordChapter,wordScene:e,parentItem:t}))},Ka=e=>{const t=document.createElement("article");t.className="word-companion-preview-item";const n=document.createElement("strong");n.textContent=`${Ga[e.action]||""} ${e.type}: ${e.wordTitle}`,t.append(n);const r=document.createElement("span");if(r.textContent=`Anchor: ${e.anchorStatus||"None"}`,t.append(r),e.match){const n=document.createElement("span");n.textContent=`Match: ${e.match}`,t.append(n)}if(Array.isArray(e.matches)&&e.matches.length>0){const n=document.createElement("div");n.className="word-companion-preview-matches";const r=document.createElement("span");r.textContent="Matches:",n.append(r);const a=document.createElement("ul");for(const t of e.matches){const e=document.createElement("li");e.textContent=t,a.append(e)}n.append(a),t.append(n)}const a=document.createElement("span");if(a.textContent=`Action: ${Ba[e.action]||e.action}`,t.append(a),e.result&&"Pending"!==e.result){const n=document.createElement("span");n.textContent=e.error?`Result: ${e.result} - ${e.error}`:`Result: ${e.result}`,t.append(n)}return t},Qa=e=>{if(te){te.innerHTML="";for(const t of Ha){const n=document.createElement("section");n.className="word-companion-preview-group";const r=document.createElement("strong");r.textContent=t.title,n.append(r);const a=Array.isArray(e?.[t.key])?e[t.key]:[];if(0===a.length){const e=document.createElement("p");e.className="word-companion-empty-list",e.textContent="None",n.append(e)}else for(const e of a)n.append(Ka(e));te.append(n)}kr()}},Xa=async e=>{const t=e.document.body.paragraphs,n=e.document.getSelection().paragraphs;t.load("text,styleBuiltIn,style"),n.load("text,styleBuiltIn,style"),await e.sync();try{for(const e of t.items)(La(e,1)||La(e,2))&&e.contentControls.load("items/tag,title");await e.sync()}catch(e){console.warn("Unable to load Word heading content controls. Continuing without PlotDirector anchors.",e)}const r=$a(t.items,n.items);return r.bodyParagraphs=t.items,r},Za=async(e,t)=>{const n=e.document.body.paragraphs,r=e.document.getSelection().paragraphs;n.load("text,styleBuiltIn,style"),r.load("text,styleBuiltIn,style"),await e.sync();const a=((e,t)=>{const n=e.map(ja),r=[];let a=0,o=0,c=null,i=null,s=0;const d=(e,t=null,n=null)=>c?(Ra(i,e.index-1),i={index:c.scenes.length+1,paragraphIndex:e.index,startParagraphIndex:e.index,endParagraphIndex:e.index,title:t||`Scene ${c.scenes.length+1}`,anchorId:n,wordCount:0},c.scenes.push(i),i):null;for(const e of n)e.text&&(La(e,1)?(Wa(c,e.index-1),a+=1,c={index:r.length+1,paragraphIndex:e.index,startParagraphIndex:e.index,endParagraphIndex:e.index,title:e.text,anchorId:e.chapterAnchorId,wordCount:0,scenes:[]},r.push(c),i=null,d(e,"Scene 1",e.sceneAnchorId),s+=e.wordCount):c&&(t&&Ta.has(e.text)?(o+=1,d(e)):(c.wordCount+=e.wordCount,i&&(i.wordCount+=e.wordCount),s+=e.wordCount)));return Wa(c,n.length-1),{paragraphs:n,chapters:r,usesExplicitScenes:!!t,paragraphCount:n.length,heading1Count:a,heading2Count:o,documentWordCount:s,currentParagraphIndex:null,currentChapter:null,currentScene:null}})(n.items,t),o=Ua(a,r.items);return mn=a,Ma(o),or("Cache rebuilt."),a},eo=async()=>{const e=mn?.currentScene;return e&&Number.isInteger(e.startParagraphIndex)&&Number.isInteger(e.endParagraphIndex)&&Gt&&Ft&&window.Word&&"function"==typeof window.Word.run?await window.Word.run(async t=>{const n=t.document.body.paragraphs;n.load("text"),await t.sync();let r=0;const a=Math.min(e.endParagraphIndex,n.items.length-1),o=mn.currentChapter?.startParagraphIndex;for(let t=e.startParagraphIndex;t<=a;t+=1){const e=String(n.items[t]?.text||"").trim();e&&!Ta.has(e)&&t!==o&&(r+=Pa(e))}return e.wordCount=r,wr(mn.currentChapter?.title,e.title,r,mn.currentChapter?.anchorId,e.anchorId,mn.currentChapter?.index),r}):zt},to=async()=>{const e=mn?.currentScene;return e&&Number.isInteger(e.startParagraphIndex)&&Number.isInteger(e.endParagraphIndex)&&Gt&&Ft&&window.Word&&"function"==typeof window.Word.run?await window.Word.run(async t=>{const n=t.document.body.paragraphs;n.load("text"),await t.sync();const r=[],a=Math.min(e.endParagraphIndex,n.items.length-1),o=mn.currentChapter?.startParagraphIndex;for(let t=e.startParagraphIndex;t<=a;t+=1){const e=String(n.items[t]?.text||"").trim();e&&!Ta.has(e)&&t!==o&&r.push(e)}return r.join("\n")}):""},no=async()=>{if(pr(""),!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return wr(null,null,null),pr("Word document access is unavailable."),aa({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;F&&(F.disabled=!0,F.textContent="Scanning..."),pr("Scanning document structure...");try{const e=await window.Word.run(async e=>{const t=ha();return t?await Za(e,!!t.usesExplicitScenes):(mn=null,await Xa(e))});return mn||wr(e.currentChapter?.title,e.currentScene?.title,e.currentScene?.wordCount,e.currentChapter?.anchorId,e.currentScene?.anchorId,e.currentChapter?.index),Vr("Not detected"),Oa(e),pr(""),aa({lastScan:"Success",lastError:"-",paragraphs:String(e.paragraphCount),heading1:String(e.heading1Count),heading2:String(e.heading2Count)}),!0}catch(e){const t=oa(e);return console.error("Unable to scan the Word document.",e),wr(null,null,null),pr(`Unable to scan the Word document: ${t}`),aa({lastScan:"Failure",lastError:t}),!1}finally{F&&(F.disabled=!1,F.textContent="Refresh Document Structure")}},ro=async()=>{const e=ha();if(!pa()||!e)return Ir("Select a project and book to analyse manuscript structure."),!1;if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return Ir("Word document access is unavailable."),aa({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;X&&(X.disabled=!0,X.textContent="Analysing..."),Ir("Analysing manuscript structure...");try{const t=await window.Word.run(async e=>await Xa(e)),n=await po(`/api/word-companion/books/${e.bookId}/structure`);return wr(t.currentChapter?.title,t.currentScene?.title,t.currentScene?.wordCount,t.currentChapter?.anchorId,t.currentScene?.anchorId,t.currentChapter?.index),Oa(t),un=((e,t)=>{const n={alreadyLinked:[],couldLink:[],wouldCreateChapters:[],wouldCreateScenes:[],manualReview:[]},r=Array.isArray(t?.chapters)?t.chapters:[];for(const t of Array.isArray(e?.chapters)?e.chapters:[]){const e=_a(t,r,n);for(const a of Ya(t))za(a,e,r,n)}return n})(t,n),Qa(un),Ir("Preview generated. No changes have been applied."),aa({lastScan:"Success",lastError:"-",paragraphs:String(t.paragraphCount),heading1:String(t.heading1Count),heading2:String(t.heading2Count)}),!0}catch(e){return console.error("Unable to analyse manuscript structure.",e),Ir("Unable to analyse manuscript structure."),aa({lastScan:"Failure",lastError:oa(e)}),!1}finally{X&&(X.textContent="Analyse Manuscript Structure",vr())}},ao=e=>{Nn&&(Nn(e),Nn=null),ut?.close?ut.close():ut&&(ut.hidden=!0)},oo=()=>{const e=((e=un)=>{const t=br(e);return{linkChapters:t.filter(e=>"couldLink"===e.category&&"Chapter"===e.type).length,linkScenes:t.filter(e=>"couldLink"===e.category&&"Scene"===e.type).length,createChapters:t.filter(e=>"wouldCreateChapters"===e.category).length,createScenes:t.filter(e=>"wouldCreateScenes"===e.category).length,manualReview:Array.isArray(e?.manualReview)?e.manualReview.length:0}})();return(e=>{if(!pt)return;pt.innerHTML="";const t=[`Link ${e.linkChapters+e.linkScenes} chapters/scenes`,`Create ${e.createChapters} chapters`,`Create ${e.createScenes} scenes`],n=document.createElement("ul");for(const e of t){const t=document.createElement("li");t.textContent=e,n.append(t)}pt.append(n)})(e),ut?new Promise(e=>{Nn=e,ut.showModal?ut.showModal():ut.hidden=!1}):Promise.resolve(window.confirm(`Apply Structure Sync?\n\nThis will:\n\n- Link ${e.linkChapters+e.linkScenes} chapters/scenes\n- Create ${e.createChapters} chapters\n- Create ${e.createScenes} scenes\n\nManual review items will be skipped.`))},co=(e,t,n="")=>{e.result=t,e.error=n},io=e=>Number.isInteger(e?.wordChapter?.index)&&e.wordChapter.index>0?10*e.wordChapter.index:null,so=e=>Number.isInteger(e?.wordScene?.index)&&e.wordScene.index>0?10*e.wordScene.index:null,lo=async(e,t)=>{const n=await ho(`/api/word-companion/books/${e}/chapters`,{title:zr(t.wordTitle),sortOrder:io(t)});if(!n?.chapterId)throw new Error("Chapter creation did not return a chapter ID.");jr(),t.pdChapter={chapterId:n.chapterId,title:n.title||t.wordTitle,sortOrder:n.sortOrder||io(t)||0,scenes:[]},t.match=`Chapter ${t.pdChapter.chapterId}: ${t.pdChapter.title}`},uo=async(e,t)=>{const n=t.pdChapter||t.parentItem?.pdChapter;if(!n?.chapterId)throw new Error("Scene parent chapter is not available.");const r=await ho(`/api/word-companion/books/${e}/chapters/${n.chapterId}/scenes`,{sceneTitle:zr(t.wordTitle),sortOrder:so(t)});if(!r?.sceneId)throw new Error("Scene creation did not return a scene ID.");jr(),t.pdChapter=n,t.pdScene={sceneId:r.sceneId,title:t.wordTitle,sortOrder:so(t)||0},t.match=`Scene ${t.pdScene.sceneId}: ${t.pdScene.title}`},po=async(e,t={})=>{const n=await window.fetch(e,{credentials:"same-origin",...t,headers:{Accept:"application/json",...t.headers||{}}});if(!n.ok)throw new Error(`Request failed: ${n.status}`);return await n.json()},ho=(e,t)=>po(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),mo=async(e="")=>{Cn=!1,bn=0,Sn=[],k&&(k.innerHTML=""),gr(C,!0),ga(!1),wa(""),gr(v,!0),e&&pr(e);const t=await wo();e&&t&&Yt&&pr(e)},yo=async(e=Zt,t=en)=>{const n=pa(),r=ha(),a=xa(),o=Number.parseInt(e||"",10),c=Number.parseInt(t||"",10);if(!n||!r||!a||!Number.isInteger(o)||o<=0||!Number.isInteger(c)||c<=0)return;const i=`${n.projectId}:${r.bookId}:${o}`;if(er!==i){er=i;try{await ho("/api/word-companion/runtime/current-scene",{documentGuid:a,projectId:n.projectId,bookId:r.bookId,chapterId:c,sceneId:o}),or("Current scene follow event sent.")}catch(e){er="",console.debug("Unable to notify PlotDirector of current scene.",e)}}},wo=async()=>{const e=ha();if(!(e&&Gt&&Ft&&window.Word&&"function"==typeof window.Word.run))return!1;pr("Reading manuscript position...");try{jr(),await Promise.all([Ro(!0),Wo(!0)]),await Xr(e.bookId);const t=await window.Word.run(async t=>await Za(t,!!e.usesExplicitScenes));return Oa(t),aa({lastScan:"Success",lastError:"-",paragraphs:String(t.paragraphCount),heading1:String(t.heading1Count),heading2:String(t.heading2Count)}),Yt?(_t?await Bo():await Ho(),Lr(!1),Er("Live"),pr(""),!0):(Vr("Not detected"),Lr(!1),Er("Live"),pr("Manuscript linked. Click inside a chapter to show the current scene."),!0)}catch(e){return console.error("Unable to initialise bound manuscript runtime.",e),mn=null,Er("Manual"),pr(`Unable to read manuscript position: ${oa(e)}`),aa({lastScan:"Failure",lastError:oa(e)}),!1}},fo=e=>e?[...e.querySelectorAll("input[type='checkbox']:checked")].map(e=>Number.parseInt(e.value||"",10)).filter(e=>Number.isInteger(e)&&e>0):[],go=()=>{const e=Number.parseInt(Le?.value||"",10);return Number.isInteger(e)&&e>0?e:null},So=(e,t,n,r)=>{const a=((e,t)=>Da(e).find(e=>qa(e.tag,t))||null)(e,r),o=a||e.getRange().insertContentControl();return o.title=t,o.tag=n,o.appearance="Hidden",o},Io=async(e="PlotDirector IDs attached successfully.")=>{if(!Zt||!en)return pr("No resolved PlotDirector scene."),!1;if((Xt&&Xt!==Zt||Qt&&Qt!==en)&&!window.confirm("This scene is already linked. Replace the existing PlotDirector link?"))return!1;if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return pr("Word document access is unavailable."),!1;se&&(se.disabled=!0,se.textContent="Attaching...");try{return await window.Word.run(async e=>{const t=await Xa(e);if(!t.currentChapter||!t.currentScene)throw new Error("No scene detected in Word. Use Heading 2 for scenes.");const n=t.bodyParagraphs[t.currentChapter.paragraphIndex],r=t.bodyParagraphs[t.currentScene.paragraphIndex];if(!n||!r)throw new Error("Unable to locate the current Word headings.");So(n,"PlotDirector Chapter",`PD-CHAPTER-${en}`,"PD-CHAPTER"),So(r,"PlotDirector Scene",`PD-SCENE-${Zt}`,"PD-SCENE"),await e.sync()}),Qt=en,Xt=Zt,rn=!1,nn="SceneID Anchor",tn="Anchor",pr(e),aa({lastError:"-"}),yr(),!0}catch(e){return console.error("Unable to attach PlotDirector IDs.",e),pr("Unable to attach PlotDirector IDs."),aa({lastError:oa(e)}),yr(),!1}finally{se&&(se.textContent=Xt===Zt?"Attach PlotDirector IDs":"Reattach PlotDirector IDs",yr())}},Co=async e=>{if(!en)return Ur("No resolved PlotDirector chapter."),!1;if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return Ur("Word document access is unavailable."),!1;try{return await window.Word.run(async e=>{const t=await Xa(e);if(!t.currentChapter)throw new Error("No chapter detected in Word. Use Heading 1 for chapters.");const n=t.bodyParagraphs[t.currentChapter.paragraphIndex];if(!n)throw new Error("Unable to locate the current Word chapter heading.");So(n,"PlotDirector Chapter",`PD-CHAPTER-${en}`,"PD-CHAPTER"),await e.sync()}),Qt=en,rn=!1,nn="ChapterID Anchor",tn="Chapter anchor",Ur(e),pr(e),aa({lastError:"-"}),yr(),!0}catch(e){return console.error("Unable to attach PlotDirector chapter ID.",e),Ur("Unable to attach PlotDirector chapter ID."),aa({lastError:oa(e)}),yr(),!1}},bo=async e=>{Hr(),await Bo(),pr(e),Ur(e)},ko=e=>{ln&&(ln(e),ln=null),ct?.close?ct.close():ct&&(ct.hidden=!0)},vo=()=>{if(!nt)return;const e=zr(tt?.value||"").toLocaleLowerCase(),t=sn.filter(t=>!e||String(t.title||"").toLocaleLowerCase().includes(e));if(nt.innerHTML="",dn=null,rt&&(rt.disabled=!0),0===t.length){const e=document.createElement("p");return e.className="word-companion-empty-list",e.textContent="No chapters found.",void nt.append(e)}for(const e of t){const t=Number.parseInt(e.chapterId||"",10);if(!Number.isInteger(t)||t<=0)continue;const n=document.createElement("label");n.className="word-companion-scene-option";const r=document.createElement("input");r.type="radio",r.name="word-companion-link-chapter",r.value=String(t),r.addEventListener("change",()=>{dn=t,rt&&(rt.disabled=!1)});const a=document.createElement("span");a.textContent=e.title||"Untitled chapter",n.append(r,a),nt.append(n)}},xo=()=>{et?.close?et.close():et&&(et.hidden=!0)},No=async(e,t,n)=>{const r=ha();if(!r)return Wr("Select a PlotDirector book first."),!1;await na(r.bookId,e,t,"Manual link","Title Match");return!!await Io(n)&&(Wr(n),Gr(),!0)},Eo=e=>{cn&&(cn(e),cn=null),ze?.close?ze.close():ze&&(ze.hidden=!0)},Lo=()=>{if(!Ve)return;const e=zr(Fe?.value||"").toLocaleLowerCase(),t=an.filter(t=>!e||String(t.title||"").toLocaleLowerCase().includes(e));if(Ve.innerHTML="",on=null,Je&&(Je.disabled=!0),0===t.length){const e=document.createElement("p");return e.className="word-companion-empty-list",e.textContent="No scenes found.",void Ve.append(e)}for(const e of t){const t=Number.parseInt(e.sceneId||"",10);if(!Number.isInteger(t)||t<=0)continue;const n=document.createElement("label");n.className="word-companion-scene-option";const r=document.createElement("input");r.type="radio",r.name="word-companion-link-scene",r.value=String(t),r.addEventListener("change",()=>{on=t,Je&&(Je.disabled=!1)});const a=document.createElement("span");a.textContent=e.title||"Untitled scene",n.append(r,a),Ve.append(n)}},Po=()=>{Ge?.close?Ge.close():Ge&&(Ge.hidden=!0)},qo=()=>{Wn=!1,Nr(),Un&&(Un=!1,Ao(1e3))},Do=async(e={})=>{const t=e.source||"manual";if(!Zt)return void Sr("No resolved PlotDirector scene.");if(!en)return void Sr("No resolved PlotDirector chapter.");if(Ln)return void Sr("Refresh Current Scene before syncing.");const n=ha(),r=xa();if(!n||!r)return void Sr("Bound manuscript metadata is unavailable.");if(Wn)return Un=!0,void or("Scene sync deferred; sync already running.");fr(),Wn=!0,Un=!1;let a=zt;try{a=await eo()}catch(e){return Sr("Sync failed"),aa({lastError:oa(e)}),or("Scene sync failed."),void qo()}if(!Number.isInteger(a)||a<0)return Sr("Sync failed"),or("Scene sync failed."),void qo();if(Mn===Zt&&On===a)return Sr("Synced"),or("Sync skipped (count unchanged)."),void qo();or("Scene word count changed."),ge&&(ge.disabled=!0,ge.textContent="Syncing..."),Sr("Syncing..."),or(`Scene sync started (${t}).`);try{const e=await ho("/api/word-companion/runtime/scene-word-count",{documentGuid:r,bookId:n.bookId,chapterId:en,sceneId:Zt,wordCount:a}),t=e?.actualWords??a,o=new Date;Mn=Zt,On=t,ra(Ie,Dr(t)),ra(he,Dr(t)),ra(Ce,Ar(o)),ra(fe,Ar(o)),Sr("Synced"),or("Scene sync succeeded.")}catch(e){Sr("Sync failed"),aa({lastError:oa(e)}),or("Scene sync failed.")}finally{ge&&(ge.textContent="Sync Current Scene"),qo()}},Ao=(e=4e3)=>{fr(),Zt&&en&&!Ln&&!Wn&&(Rn=window.setTimeout(()=>{Rn=null,Do({source:"automatic"})},e))},$o=()=>{Hn&&(window.clearTimeout(Hn),Hn=null)},To=()=>{Fn=null,Vn="",Jn=[],Yn=null,_n="",$o()},jo=()=>{zn=null,Kn="",Qn=[],Xn=null,Zn=""},Ro=async(e=!1)=>{const t=pa(),n=xa();if(!t||!n)return Jn=[],[];if(!e&&Fn===t.projectId&&Vn===n&&Jn.length>0)return Jn;const r=await po(`/api/word-companion/runtime/characters?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(n)}`);return Fn=t.projectId,Vn=n,Jn=Array.isArray(r?.characters)?r.characters:[],or("Character alias cache refreshed."),Jn},Wo=async(e=!1)=>{const t=pa(),n=xa();if(!t||!n)return Qn=[],[];if(!e&&zn===t.projectId&&Kn===n&&Qn.length>0)return Qn;const r=await po(`/api/word-companion/runtime/assets?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(n)}`);return zn=t.projectId,Kn=n,Qn=Array.isArray(r?.assets)?r.assets:[],or(`Asset cache loaded: ${Qn.length} aliases.`),Qn},Uo=(e,t)=>{const n=String(t||"").trim();if(!n)return!1;const r=(a=n,String(a||"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).replace(/\s+/g,"\\s+");var a;return new RegExp(`(^|[^\\p{L}\\p{N}_])${r}(?=$|[^\\p{L}\\p{N}_])`,"iu").test(e)},Mo=async()=>{if(Hn=null,Zt&&!Ln&&xa()){if(Bn)return Gn=!0,void or("Character suggestion detection deferred; detection already running.");Bn=!0,Gn=!1;try{const[e,t,n]=await Promise.all([to(),Ro(),Wo()]),r=((e,t)=>{if(!e||!Array.isArray(t)||0===t.length)return[];const n=new Map;for(const r of t){const t=Number.parseInt(r.characterId||"",10);!Number.isInteger(t)||t<=0||n.has(t)||Uo(e,r.matchText)&&n.set(t,r.name||r.matchText||"Character")}return[...n.entries()].map(([e,t])=>({characterId:e,name:t}))})(e,t),a=r.map(e=>e.characterId),o=a.slice().sort((e,t)=>e-t).join(","),c=((e,t)=>{if(!e||!Array.isArray(t)||0===t.length)return[];const n=new Map;for(const r of t){const t=Number.parseInt(r.assetId||"",10);!Number.isInteger(t)||t<=0||n.has(t)||Uo(e,r.matchText)&&n.set(t,r.name||r.matchText||"Asset")}return[...n.entries()].map(([e,t])=>({assetId:e,name:t}))})(e,n),i=c.map(e=>e.assetId),s=i.slice().sort((e,t)=>e-t).join(",");if(!o||Yn===Zt&&_n===o)or("Character suggestions skipped.");else{const e=await ho("/api/word-companion/runtime/character-suggestions",{documentGuid:xa(),sceneId:Zt,characterIds:a});if(Yn=Zt,_n=o,(e?.createdCount||0)>0){const t=r.slice(0,3).map(e=>e.name).join(", "),n=r.length>3?" +"+(r.length-3):"";pr(t?`Characters detected: ${t}${n}`:e.message)}or(e?.message||"Character suggestions submitted.")}if(!s||Xn===Zt&&Zn===s)or("Asset suggestions skipped.");else{or(`Asset matches found: ${c.map(e=>e.name).join(", ")}`);const e=await ho("/api/word-companion/runtime/asset-suggestions",{documentGuid:xa(),sceneId:Zt,assetIds:i});if(Xn=Zt,Zn=s,(e?.createdCount||0)>0){const t=c.slice(0,3).map(e=>e.name).join(", "),n=c.length>3?" +"+(c.length-3):"";pr(t?`Assets detected: ${t}${n}`:e.message)}or(e?.message||"Asset suggestions submitted.")}}catch(e){console.error("Unable to detect runtime suggestions.",e),aa({lastError:oa(e)})}finally{Bn=!1,Gn&&(Gn=!1,Oo(1500))}}},Oo=(e=2500)=>{$o(),!Zt||Ln||Bn?Bn&&(Gn=!0):Hn=window.setTimeout(()=>{Mo()},e)},Ho=async()=>{const e=pa(),t=ha(),n=Kr(Yt,"chapter");if(Qr({projectId:e?.projectId,projectTitle:e?.title,bookId:t?.bookId,bookTitle:t?ua(t):void 0,detectedChapter:Yt,detectedScene:_t,requestChapter:n,requestScene:"",result:"Not run",chapterId:null,sceneId:null}),!t)return Vr("Not detected"),pr("Select a PlotDirector book first."),!1;if(!Yt)return Vr("Not detected"),pr("No chapter detected in Word. Use Heading 1 for chapters."),!1;Vr("Not detected");try{const e=await Zr(t.bookId),r=Qt?e.find(e=>e.chapterId===Qt):null,a=n.toLocaleLowerCase(),o=a?e.find(e=>Kr(e.title,"chapter").toLocaleLowerCase()===a):null,c=r||o;return c?(Hr(),Pr(null,c.chapterId,r?"Chapter anchor":"Chapter title"),nn=r?"ChapterID Anchor":"Title Match",hr("Chapter linked to PlotDirector"),pr("No scene detected in Word. Use Heading 2 for scenes."),Qr({result:"Chapter matched",chapterId:c.chapterId,sceneId:null}),!0):(Pr(null),hr("Chapter not found in PlotDirector."),pr("Chapter not found in PlotDirector."),Qr({result:"Chapter not matched",chapterId:null,sceneId:null}),Br("Chapter not found in PlotDirector."),!1)}catch(e){return Vr("Not found in PlotDirector"),aa({lastError:oa(e)}),pr("Unable to load PlotDirector chapter data."),!1}},Bo=async()=>{const e=pa(),t=ha(),n=Kr(Yt,"chapter"),r=Kr(_t,"scene");if(Qr({projectId:e?.projectId,projectTitle:e?.title,bookId:t?.bookId,bookTitle:t?ua(t):void 0,detectedChapter:Yt,detectedScene:_t,requestChapter:n,requestScene:r,result:"Not run",chapterId:null,sceneId:null}),mr({anchorType:Xt?"SceneID Anchor":Qt?"ChapterID Anchor":"Title Match",storedSceneId:Xt,storedChapterId:Qt,resolutionMethod:"-"}),!t)return Vr("Not detected"),pr("Select a PlotDirector book first."),Qr({result:"Error"}),!1;if(!Yt||!_t)return Vr("Not detected"),pr("No scene detected in Word. Use Heading 2 for scenes."),Qr({result:"Error"}),!1;ne&&(ne.disabled=!0,ne.textContent="Refreshing...");const a=()=>{ne&&(ne.disabled=!1,ne.textContent="Refresh PlotDirector Scene")};Vr("Not detected"),pr("Resolving PlotDirector scene...");try{if(Xt){const e=await(async(e,t)=>{const n=await po(`/api/word-companion/books/${e}/structure`),r=Array.isArray(n?.chapters)?n.chapters:[];for(const e of r){const n=Array.isArray(e.scenes)?e.scenes:[];for(const r of n)if(t(e,r))return{chapter:e,scene:r}}return null})(t.bookId,(e,t)=>t.sceneId===Xt);if(e)return Qr({result:"Matched",chapterId:e.chapter.chapterId,sceneId:e.scene.sceneId}),await na(t.bookId,e.scene.sceneId,e.chapter.chapterId,"Anchor","SceneID Anchor"),!0;rn=!0,nn="SceneID Anchor",hr("Not found in PlotDirector"),pr("Stored PlotDirector ID is invalid."),Qr({result:"Error",chapterId:Qt,sceneId:Xt}),mr({anchorType:"SceneID Anchor",storedSceneId:Xt,storedChapterId:Qt,resolutionMethod:"Anchor"})}if(Qt){const e=(await Xr(t.bookId)).find(e=>e.chapterId===Qt),n=e?(Array.isArray(e.scenes)?e.scenes:[]).find(e=>Kr(e.title,"scene").toLocaleLowerCase()===r.toLocaleLowerCase()):null;if(n)return Qr({result:"Matched",chapterId:e.chapterId,sceneId:n.sceneId}),await na(t.bookId,n.sceneId,e.chapterId,"Anchor","ChapterID Anchor"),!0;e&&!Xt?(nn="ChapterID Anchor",Pr(null,Qt,"Chapter anchor"),Qr({result:"Chapter matched",chapterId:Qt,sceneId:null})):Xt||(nn="ChapterID Anchor",Qr({result:"Chapter anchor not found",chapterId:Qt,sceneId:null}))}const e=await ho(`/api/word-companion/books/${t.bookId}/resolve-scene`,{chapterTitle:n,sceneTitle:r});if(!e?.matched||!e.sceneId){const t=rn,n=Number.parseInt(e?.chapterId||"",10),r=Number.isInteger(en)&&en>0?en:null,o=Number.isInteger(n)&&n>0?n:r,c=!!e?.chapterMatched||!!o;return Vr("Not found in PlotDirector"),rn=t,c&&(Pr(null,o,o===r?"Chapter anchor":"Chapter title"),hr("Scene not found in PlotDirector.")),pr(t?"Stored PlotDirector ID is invalid.":c?"Scene not found in PlotDirector.":"This chapter does not exist in PlotDirector. Create or link the chapter first."),Qr({result:"Not matched",chapterId:c?o:e?.chapterId,sceneId:e?.sceneId}),t||(c?(Hr(),Fr("Scene not found in PlotDirector.")):(Gr(),Br("Chapter not found in PlotDirector."))),a(),!1}const o=rn;return Qr({result:o?"Matched by title fallback":"Matched",chapterId:e.chapterId,sceneId:e.sceneId}),await na(t.bookId,e.sceneId,e.chapterId,o?"Title fallback":"Title","Title Match"),o&&(rn=!0,pr("Stored PlotDirector ID is invalid."),yr()),!0}catch(e){const t=rn;return aa({lastError:oa(e)}),Vr("Not found in PlotDirector"),rn=t,pr(t?"Stored PlotDirector ID is invalid.":"Unable to load PlotDirector scene data."),Qr({result:"Error"}),!1}finally{a()}},Go=async()=>{if(Pn=null,jn)return An=!0,void or("Runtime update deferred; update already running.");if(!Ot||!ha())return qn=!1,void or("Runtime update skipped.");if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return qn=!1,Er("Manual"),void pr("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");if(!mn)return qn=!1,Er("Manual"),void pr("Document structure is not cached yet. Use Refresh Current Scene.");const e=Date.now()-Dn;if(qn&&e<$n)return or("Runtime update skipped (typing active)."),void Fo($n-e);jn=!0,qn=!1,An=!1,Er("Updating..."),or("Runtime update executed.");try{const e=await window.Word.run(async e=>await(async e=>{const t=e.document.getSelection().paragraphs;return t.load("text,styleBuiltIn,style"),await e.sync(),t.items})(e)),t=Ua(mn,e),n=Ma(t);if(await eo(),!n)return Lr(!1),Er("Current scene updated"),Ao(),void Oo();_t?await Bo():await Ho(),Lr(!1),Er("Current scene updated"),pr("Current scene updated."),Ao(),Oo()}catch(e){console.error("Unable to refresh current scene from Word selection.",e),aa({lastError:oa(e)}),Lr(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving.")}finally{jn=!1,(An||qn)&&(An=!1,Fo($n))}},Fo=(e=1200)=>{Pn&&window.clearTimeout(Pn),Pn=window.setTimeout(Go,Math.max(0,e)),Er("Waiting for typing to pause"),or("Runtime update scheduled.")},Vo=()=>{((e="selection",t=1200)=>{if(qn=!0,Dn=Date.now(),fr(),$o(),or(`${e} changed.`),jn)return An=!0,void Er("Waiting for typing to pause");Fo(t)})("Selection")},Jo=()=>{if(Tn&&window.Office?.context?.document&&"function"==typeof window.Office.context.document.removeHandlerAsync&&window.Office?.EventType?.DocumentSelectionChanged)try{window.Office.context.document.removeHandlerAsync(window.Office.EventType.DocumentSelectionChanged,{handler:Vo}),Tn=!1}catch(e){console.warn("Unable to remove Word selection tracking handler.",e)}},Yo=async(e,n)=>{if(mn=null,jr(),!e)return Bt=[],da(O,"Select a project first"),da(m,"Select a project first"),ur(""),sa(t,null),Na(),Vr("Not detected"),void Cr();da(O,"Loading books..."),ur(""),Vr("Not detected"),Cr("Select a book to analyse manuscript structure.");try{const r=await po(`/api/word-companion/projects/${e}/books`);if(Bt=Array.isArray(r.books)?r.books:[],0===Bt.length)return da(O,"No books available."),da(m,"No books available."),ur("No books available."),sa(t,null),Na(),void Ia("No books available.");la(O,"Choose a book",Bt.map(e=>({...e,displayTitle:ua(e)})),"bookId","displayTitle");const a=Bt.find(e=>e.bookId===n);a&&O?(O.value=String(a.bookId),sa(t,a.bookId)):sa(t,null),((e=null)=>{if(!m)return;if(0===Bt.length)return void da(m,"No books available.");la(m,"Choose a book",Bt.map(e=>({...e,displayTitle:ua(e)})),"bookId","displayTitle");const t=e||Number.parseInt(O?.value||"",10),n=Bt.find(e=>e.bookId===t);n&&(m.value=String(n.bookId)),fa()})(a?.bookId||n),Na(),Vr((ha(),"Not detected")),Cr(ha()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure."),Ia(ya()?"Ready to scan manuscript structure.":"Select a Book to begin.")}catch{Bt=[],da(O,"Unable to load books."),da(m,"Unable to load books."),ur("Unable to load books."),sa(t,null),Na(),Vr("Not detected"),Cr("Unable to load books."),Ia("Unable to load books.")}};for(const e of l)e.addEventListener("click",()=>ir(e.dataset.tabButton));sr(),M?.addEventListener("change",async()=>{const n=Number.parseInt(M.value||"",10);Tr(),h&&Number.isInteger(n)&&n>0&&(h.value=String(n)),sa(e,Number.isInteger(n)&&n>0?n:null),sa(t,null),Vr("Not detected"),Cr(),Ia("Select a Book to begin."),await Yo(n,null)}),O?.addEventListener("change",()=>{const e=Number.parseInt(O.value||"",10);Tr(),sa(t,Number.isInteger(e)&&e>0?e:null),m&&Number.isInteger(e)&&e>0&&(m.value=String(e)),Na(),Vr("Not detected"),Cr(ha()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure."),Ia(ya()?"Ready to scan manuscript structure.":"Select a Book to begin.")}),h?.addEventListener("change",async()=>{const n=Number.parseInt(h.value||"",10);Tr(),M&&Number.isInteger(n)&&n>0&&(M.value=String(n)),sa(e,Number.isInteger(n)&&n>0?n:null),sa(t,null),Ia("Select a Book to begin."),await Yo(n,null)}),m?.addEventListener("change",()=>{const e=Number.parseInt(m.value||"",10);Tr(),O&&Number.isInteger(e)&&e>0&&(O.value=String(e)),sa(t,Number.isInteger(e)&&e>0?e:null),Na(),Ia(ya()?"Ready to scan manuscript structure.":"Select a Book to begin.")}),y?.addEventListener("input",fa),w?.addEventListener("click",async()=>{const e=ma(),t=String(y?.value||"").trim();if(e&&t){w.disabled=!0,wa("Creating Book...");try{const n=await ho(`/api/word-companion/projects/${e.projectId}/books`,{title:t});y&&(y.value=""),M&&(M.value=String(e.projectId)),await Yo(e.projectId,n.bookId),m&&(m.value=String(n.bookId)),wa("Ready to scan manuscript structure.")}catch(e){console.error("Unable to create Book from Word Companion.",e),wa(`Unable to create Book: ${oa(e)}`)}finally{fa()}}else fa()}),f?.addEventListener("click",async()=>{const e=ma(),t=ya();if(e&&t)if(Gt&&Ft&&window.Word&&"function"==typeof window.Word.run){f&&(f.disabled=!0,f.textContent="Scanning..."),wa("Scanning manuscript structure...");try{const n=await window.Word.run(async e=>{const n=e.document.body.paragraphs;return n.load("text,styleBuiltIn,style"),await e.sync(),((e,t)=>{const n=[];let r=null,a=null,o=0;const c=[],i=new Set(["***","###"]),s=()=>{if(!r)return null;const e={title:`Scene ${r.scenes.length+1}`,sortOrder:10*(r.scenes.length+1),wordCount:0};return r.scenes.push(e),e};return e.forEach(e=>{const d=String(e.text||"").trim();if(!d)return;if(c.push(d),La(e,1))return r={title:d,sortOrder:10*(n.length+1),wordCount:0,scenes:[]},n.push(r),a=s(),void(o+=Pa(d));if(!r||!a)return;if(t&&i.has(d))return void(a=s());const l=Pa(d);r.wordCount+=l,a.wordCount+=l,o+=l}),{chapters:n,chapterCount:n.length,sceneCount:n.reduce((e,t)=>e+t.scenes.length,0),wordCount:o,documentText:c.join("\n")}})(n.items,!!t.usesExplicitScenes)});gn=n,In=!1;const r=await ho("/api/word-companion/manuscript/analyse",{projectId:e.projectId,bookId:t.bookId,documentGuid:va(),chapterCount:n.chapterCount,sceneCount:n.sceneCount,wordCount:n.wordCount});fn=r,(e=>{if(!I)return;I.innerHTML="";const t=document.createElement("strong");t.textContent="Manuscript Analysis",I.append(t);const n=document.createElement("dl"),r=[["Project",e.projectTitle],["Book",ua({title:e.bookTitle,subtitle:e.bookSubtitle})],["Chapters",Number(e.chapterCount||0).toLocaleString()],["Scenes",Number(e.sceneCount||0).toLocaleString()],["Words",Number(e.wordCount||0).toLocaleString()]];for(const[e,t]of r){const r=document.createElement("dt");r.textContent=e;const a=document.createElement("dd");a.textContent=t||"-",n.append(r,a)}I.append(n),gr(I,!1),gr(L,!1),wa(e.message||"Preview generated."),fa()})(r);try{const t=await ho("/api/word-companion/manuscript/discover-characters",{projectId:e.projectId,documentText:n.documentText||""});Sn=Array.isArray(t?.candidates)?t.candidates:[],gr(C,!0),gr(v,!0)}catch(e){console.error("Unable to discover character candidates.",e),Sn=[],gr(C,!0),gr(v,!0)}aa({lastScan:"Success",lastError:"-",paragraphs:"-",heading1:String(n.chapterCount),heading2:"-"})}catch(e){console.error("Unable to scan manuscript for first-run import.",e),Ia(`Unable to scan manuscript: ${oa(e)}`),aa({lastScan:"Failure",lastError:oa(e)})}finally{f&&(f.textContent="Scan Manuscript"),fa()}}else Ia("Word document access is unavailable.");else Ia("Select a Project and Book to begin.")}),P?.addEventListener("click",async()=>{const n=ma(),i=ya();if(!(n&&i&&gn&&fn?.canImport))return void fa();let s=!1;if(!fn.requiresReplaceConfirmation||(s=await new Promise(e=>{if(!D||"function"!=typeof D.showModal)return void e(window.confirm("This Book already contains planned chapters and scenes.\n\nImporting this manuscript will replace the planned structure.\n\nContinue?"));const t=t=>{A?.removeEventListener("click",n),$?.removeEventListener("click",r),D?.removeEventListener("cancel",a),D?.close(),e(t)},n=()=>t(!0),r=()=>t(!1),a=e=>{e.preventDefault(),t(!1)};A?.addEventListener("click",n),$?.addEventListener("click",r),D?.addEventListener("cancel",a),D.showModal()}),s)){kn=!0,fa(),wa("Importing manuscript structure...");try{const l=va(),u=await ho("/api/word-companion/manuscript/import",{projectId:n.projectId,bookId:i.bookId,documentGuid:l,bindingVersion:1,replacePlanned:s,chapters:gn.chapters});if(!u.imported)return fn={...fn,canImport:!u.requiresReplaceConfirmation,requiresReplaceConfirmation:!!u.requiresReplaceConfirmation,message:u.message||fn.message},wa(u.message||"Import was not completed."),void fa();const p=u.manuscriptDocument;await(d={documentGuid:p?.documentGuid||l,bookId:u.bookId,projectId:u.projectId,bindingVersion:p?.bindingVersion||1},new Promise((e,t)=>{const n=window.Office?.context?.document?.settings;n?(n.set(r,d.documentGuid),n.set(a,String(d.bookId)),n.set(o,String(d.projectId)),n.set(c,String(d.bindingVersion||1)),n.saveAsync(n=>{n.status===window.Office.AsyncResultStatus.Succeeded?e():t(n.error||new Error("Unable to save Word document metadata."))})):t(new Error("Word document settings are unavailable."))})),pn={documentGuid:p?.documentGuid||l,bookId:u.bookId,projectId:u.projectId,bindingVersion:p?.bindingVersion||1},sa(e,u.projectId),sa(t,u.bookId),M&&(M.value=String(u.projectId));const h=Sn;await Yo(u.projectId,u.bookId),dr("Connected"),In=!0,Cn=h.length>0,bn=Cn?Date.now():0,Sn=h,h.length>0?(ga(!0),ba(h),gr(L,!0),gr(v,!1),wa(u.message||"Manuscript structure imported."),pr(u.message||"Manuscript structure imported."),window.setTimeout(fa,750)):await mo(u.message||"Manuscript structure imported.")}catch(e){console.error("Unable to import manuscript structure.",e),wa(`Unable to import manuscript: ${oa(e)}`)}finally{kn=!1,fa()}var d}else wa("Import cancelled.")}),x?.addEventListener("click",async()=>{const e=ma()||pa(),t=Ca();if(!Cn||Date.now()-bn<750||!e||0===t.length)fa();else{vn=!0,fa(),ra(b,"Creating selected characters...");try{const n=await ho("/api/word-companion/manuscript/create-discovered-characters",{projectId:e.projectId,candidateNames:t});pr(n.message||"Characters created."),ra(b,`${n.createdCount||0} created, ${n.skippedCount||0} already existed.`),await mo(n.message||"Characters created.")}catch(e){console.error("Unable to create discovered characters.",e),ra(b,`Unable to create characters: ${oa(e)}`)}finally{vn=!1,fa()}}}),N?.addEventListener("click",()=>mo("Character creation skipped.")),E?.addEventListener("click",()=>mo()),g?.addEventListener("click",()=>ga(!1)),q?.addEventListener("click",()=>Ia("Import cancelled.")),F?.addEventListener("click",no),X?.addEventListener("click",ro),Z?.addEventListener("click",async()=>{const e=ha();if(!e||0===br().length||xn)return void kr();if(!await oo())return;xn=!0,vr(),Ir("Applying structure sync...");const t={createdChapters:0,createdScenes:0,linkedChapters:0,linkedScenes:0,skipped:Array.isArray(un?.manualReview)?un.manualReview.length:0,failed:0},n=br().filter(e=>"couldLink"===e.category&&"Chapter"===e.type),r=br().filter(e=>"wouldCreateChapters"===e.category),a=br().filter(e=>"couldLink"===e.category&&"Scene"===e.type),o=br().filter(e=>"wouldCreateScenes"===e.category),c=[];let i="";const s=(e,t)=>{c.push({item:e,counterName:t})},d=async(e,n)=>{try{await(async e=>{if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)throw new Error("Word document access is unavailable.");await window.Word.run(async t=>{const n=await Xa(t),r="Chapter"===e.type?e.wordChapter:e.wordScene,a=Number.isInteger(r?.paragraphIndex)?n.bodyParagraphs[r.paragraphIndex]:null;if(!a)throw new Error("Unable to locate the Word heading.");if("Chapter"===e.type){const t=e.pdChapter?.chapterId;if(!t)throw new Error("Chapter ID is not available.");So(a,"PlotDirector Chapter",`PD-CHAPTER-${t}`,"PD-CHAPTER")}else{const t=e.pdScene?.sceneId;if(!t)throw new Error("Scene ID is not available.");So(a,"PlotDirector Scene",`PD-SCENE-${t}`,"PD-SCENE")}await t.sync()})})(e),co(e,"Success"),t[n]+=1}catch(n){co(e,"Failed",oa(n)),t.failed+=1}};try{for(const e of n)s(e,"linkedChapters");for(const n of r)try{await lo(e.bookId,n),s(n,"createdChapters")}catch(e){co(n,"Failed",oa(e)),t.failed+=1}for(const e of a)s(e,"linkedScenes");for(const n of o)try{await uo(e.bookId,n),s(n,"createdScenes")}catch(e){co(n,"Failed",oa(e)),t.failed+=1}for(const e of c)await d(e.item,e.counterName);for(const e of un.manualReview||[])co(e,"Skipped");Qa(un),i=(e=>`Structure Sync Complete. Created: ${e.createdChapters} Chapters, ${e.createdScenes} Scenes. Linked: ${e.linkedChapters} Chapters, ${e.linkedScenes} Scenes. Skipped: ${e.skipped} Manual Review items. Failed: ${e.failed} Items.`)(t),Ir(i)}finally{xn=!1,vr(),i&&(jr(),await ro(),Ir(`${i} Preview refreshed.`))}}),ht?.addEventListener("click",()=>ao(!0)),mt?.addEventListener("click",()=>ao(!1)),ut?.addEventListener("cancel",e=>{e.preventDefault(),ao(!1)}),ne?.addEventListener("click",Bo),G?.addEventListener("click",async()=>{if(!ha())return pr("Select a PlotDirector book first."),void Vr("Not detected");Pn&&(window.clearTimeout(Pn),Pn=null),qn=!1,An=!1,qr(!0),Er("Updating...");try{await Promise.all([Ro(!0),Wo(!0)]);if(!await no())return;if(Lr(!1),!_t)return await Ho(),void Er("Current scene updated");await Bo(),Er("Current scene updated")}finally{qr(!1)}}),ge?.addEventListener("click",()=>Do({source:"manual"})),Pe?.addEventListener("click",async()=>{if(Zt)if(!Ln&&await(async()=>{if(!Zt)return!1;if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return Lr(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1;try{const e=await window.Word.run(async e=>await Xa(e)),t=e.currentChapter?.title||"",n=e.currentScene?.title||"",r=e.currentScene?.anchorId||null,a=e.currentChapter?.anchorId||null,o=Number.isInteger(r)&&r===Zt,c=Number.isInteger(a)&&a===en,i=Kr(n,"scene").toLocaleLowerCase()===Kr(tr||_t,"scene").toLocaleLowerCase(),s=Kr(t,"chapter").toLocaleLowerCase()===Kr(nr||Yt,"chapter").toLocaleLowerCase();return o||i&&(c||s)?(Lr(!1),!0):(Lr(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1)}catch(e){return console.error("Unable to verify current Word scene before saving.",e),aa({lastError:oa(e)}),Lr(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1}})()){Pe&&(Pe.disabled=!0,Pe.textContent="Saving...");try{await(e=`/api/word-companion/scenes/${Zt}/links`,t={characterIds:fo(Ne),assetIds:fo(Ee),locationIds:[],primaryLocationId:go()},po(e,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})),(()=>{const e=new Set(fo(Ne)),t=new Set(fo(Ee));ar={characters:ar.characters.map(t=>({...t,linked:e.has(Number.parseInt(Jr(t,"character"),10))})),assets:ar.assets.map(e=>({...e,linked:t.has(Number.parseInt(Jr(e,"asset"),10))})),locations:ar.locations,primaryLocationId:go()}})(),Rr("Scene links saved successfully."),aa({lastError:"-"})}catch(e){Rr("Unable to save scene links."),aa({lastError:oa(e)})}finally{Pe&&(Pe.disabled=!Zt||Ln,Pe.textContent="Save Scene Links")}var e,t}else Rr("The Word cursor is now in a different scene. Refresh Current Scene before saving.");else Rr("Link a PlotDirector scene first.")}),se?.addEventListener("click",async()=>{await Io()}),Te?.addEventListener("click",async()=>{const e=ha();if(!e||!Yt||en)return void Br("Chapter not found in PlotDirector.");const t=zr(Yt),n=await((e,t)=>(ra(it,`"${e}"`),ra(st,`"${t}"`),ct?new Promise(e=>{ln=e,ct.showModal?ct.showModal():ct.hidden=!1}):Promise.resolve(window.confirm(`Create PlotDirector chapter:\n\n"${e}"\n\nin book:\n\n"${t}"\n\n?`))))(t,ua(e)||"selected book");if(n){Te&&(Te.disabled=!0,Te.textContent="Creating...");try{const n=Number.isInteger(Kt)&&Kt>0?10*Kt:null,r=await ho(`/api/word-companion/books/${e.bookId}/chapters`,{title:t,sortOrder:n});if(!r?.chapterId)throw new Error("Chapter creation did not return a chapter ID.");jr(),Pr(null,r.chapterId,"Manual chapter link");if(!await Co("Chapter created and linked successfully."))return;await bo("Chapter created and linked successfully.")}catch(e){Ur("Unable to create chapter."),aa({lastError:oa(e)})}finally{Te&&(Te.disabled=!Mr(),Te.textContent="Create Chapter in PlotDirector")}}}),je?.addEventListener("click",async()=>{const e=ha();if(e&&Yt&&!en){je&&(je.disabled=!0,je.textContent="Loading...");try{sn=await Zr(e.bookId),dn=null,tt&&(tt.value=""),ra(ot,""),vo(),et?.showModal?et.showModal():et&&(et.hidden=!1)}catch(e){Ur("Unable to load chapters."),aa({lastError:oa(e)})}finally{je&&(je.disabled=!Mr(),je.textContent="Link to Existing Chapter")}}else Br("Chapter not found in PlotDirector.")}),tt?.addEventListener("input",vo),rt?.addEventListener("click",async()=>{const e=sn.find(e=>e.chapterId===dn);if(e){rt&&(rt.disabled=!0,rt.textContent="Linking...");try{Pr(null,e.chapterId,"Manual chapter link");if(!await Co("Chapter linked successfully."))return;xo(),await bo("Chapter linked successfully.")}catch(e){ra(ot,"Unable to link chapter."),Ur("Unable to link chapter."),aa({lastError:oa(e)})}finally{rt&&(rt.disabled=!dn,rt.textContent="Link Chapter")}}else ra(ot,"Select a chapter.")}),at?.addEventListener("click",xo),dt?.addEventListener("click",()=>ko(!0)),lt?.addEventListener("click",()=>ko(!1)),ct?.addEventListener("cancel",e=>{e.preventDefault(),ko(!1)}),Oe?.addEventListener("click",async()=>{const e=ha();if(!e||!_t)return void Fr("Scene not found in PlotDirector.");const t=Kr(_t,"scene"),n=Kr(Yt,"chapter"),r=await((e,t)=>(ra(Ke,`"${e}"`),ra(Qe,`"${t}"`),ze?new Promise(e=>{cn=e,ze.showModal?ze.showModal():ze.hidden=!1}):Promise.resolve(window.confirm(`Create PlotDirector scene:\n\n"${e}"\n\nwithin chapter:\n\n"${t}"\n\n?`))))(t,n);if(r){Oe&&(Oe.disabled=!0,Oe.textContent="Creating...");try{const n=await ta();if(!n)return void Fr("This chapter does not exist in PlotDirector. Create or link the chapter first.");const r=await ho(`/api/word-companion/books/${e.bookId}/chapters/${n.chapterId}/scenes`,{sceneTitle:t});if(!r?.sceneId||!r?.chapterId)throw new Error("Scene creation did not return a scene ID.");jr(),await No(r.sceneId,r.chapterId,"Scene created and linked successfully.")}catch(e){Wr("Unable to create scene."),aa({lastError:oa(e)})}finally{Oe&&(Oe.disabled=!Or(),Oe.textContent="Create Scene in PlotDirector")}}}),He?.addEventListener("click",async()=>{const e=ha();if(e&&_t){He&&(He.disabled=!0,He.textContent="Loading...");try{const t=await Xr(e.bookId),n=ea(t);if(!n)return void Fr("This chapter does not exist in PlotDirector. Create or link the chapter first.");an=Array.isArray(n.scenes)?n.scenes:[],on=null,Fe&&(Fe.value=""),ra(_e,""),Lo(),Ge?.showModal?Ge.showModal():Ge&&(Ge.hidden=!1)}catch(e){Wr("Unable to load scenes."),aa({lastError:oa(e)})}finally{He&&(He.disabled=!Or(),He.textContent="Link to Existing Scene")}}else Fr("Scene not found in PlotDirector.")}),Fe?.addEventListener("input",Lo),Je?.addEventListener("click",async()=>{const e=ha(),t=an.find(e=>e.sceneId===on);if(e&&t){Je&&(Je.disabled=!0,Je.textContent="Linking...");try{const e=await ta();if(!e)throw new Error("This chapter does not exist in PlotDirector. Create or link the chapter first.");Po(),await No(t.sceneId,e.chapterId,"Scene linked successfully.")}catch(e){ra(_e,"Unable to link scene."),Wr("Unable to link scene."),aa({lastError:oa(e)})}finally{Je&&(Je.disabled=!on,Je.textContent="Link Scene")}}else ra(_e,"Select a scene.")}),Ye?.addEventListener("click",Po),Xe?.addEventListener("click",()=>Eo(!0)),Ze?.addEventListener("click",()=>Eo(!1)),ze?.addEventListener("cancel",e=>{e.preventDefault(),Eo(!1)}),Nt?.addEventListener("click",async()=>{Nt&&(Nt.disabled=!0,Nt.textContent="Running...");try{if(await ca(),!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return void aa({lastScan:"Failure",lastError:"Word document access is unavailable.",paragraphs:"-",heading1:"-",heading2:"-"});const e=await window.Word.run(async e=>{const t=e.document.body.paragraphs;return t.load("items"),await e.sync(),t.items.length});aa({lastScan:"Success",lastError:"-",paragraphs:String(e)})}catch(e){console.error("Word Companion diagnostics failed.",e);const t=oa(e);aa({lastScan:"Failure",lastError:t}),pr(`Unable to scan the Word document: ${t}`)}finally{Nt&&(Nt.disabled=!1,Nt.textContent="Run Diagnostics")}});const _o=Ot?(async()=>{da(M,"Loading projects..."),da(O,"Select a project first"),da(h,"Loading projects..."),da(m,"Select a project first"),lr(""),ur("");try{const n=await po("/api/word-companion/projects");if(Ht=Array.isArray(n.projects)?n.projects:[],0===Ht.length)return da(M,"No projects available."),da(h,"No projects available."),lr("No projects available."),sa(e,null),sa(t,null),Na(),void Ia("No projects available.");la(M,"Choose a project",Ht,"projectId","title"),Sa();const r=ia(e),a=Ht.find(e=>e.projectId===r);a&&M?(M.value=String(a.projectId),h&&(h.value=String(a.projectId)),sa(e,a.projectId),await Yo(a.projectId,ia(t))):(sa(e,null),sa(t,null),Na(),Ia("Select a Project and Book to begin."))}catch{Ht=[],Bt=[],da(M,"Unable to connect to PlotDirector."),da(O,"Select a project first"),da(h,"Unable to connect to PlotDirector."),da(m,"Select a project first"),dr("Unable to connect to PlotDirector."),lr("Unable to connect to PlotDirector."),sa(e,null),sa(t,null),Na(),Ia("Unable to connect to PlotDirector.")}})():Promise.resolve();if(Ot||(da(M,"Please sign in to PlotDirector."),da(O,"Please sign in to PlotDirector."),da(h,"Please sign in to PlotDirector."),da(m,"Please sign in to PlotDirector."),Na()),!window.Office||"function"!=typeof window.Office.onReady)return cr("Word Companion ready"),pr("Word document access is unavailable."),Er("Manual"),void aa({host:"Unavailable",platform:"Unavailable",ready:"No",wordApi:"No"});ca().then(async()=>{cr("Word Companion ready"),await _o,await(async()=>{if(!Ot||!Ft)return void ga(!1);const n=ka();if(n)try{const r=await po(`/api/word-companion/runtime/book/${n.bookId}?documentGuid=${encodeURIComponent(n.documentGuid)}`),a=r?.manuscriptDocument;if(r?.bookId===n.bookId&&r?.projectId===n.projectId&&a&&String(a.documentGuid).toLowerCase()===n.documentGuid.toLowerCase())return pn=n,$r(r),sa(e,r.projectId),sa(t,r.bookId),M&&(M.value=String(r.projectId)),await Yo(r.projectId,r.bookId),ga(!1),dr("Connected"),ur("Bound manuscript detected."),void await wo()}catch{}pn=null,Tr(),Sa(),ma()?await Yo(ma().projectId,null):da(m,"Select a project first"),Ia("Select a Project and Book to begin."),ga(!0)})(),Ft?(()=>{if(Ot){if(!window.Office?.context?.document||"function"!=typeof window.Office.context.document.addHandlerAsync||!window.Office?.EventType?.DocumentSelectionChanged)return Er("Manual"),void pr("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");try{window.Office.context.document.addHandlerAsync(window.Office.EventType.DocumentSelectionChanged,Vo,e=>{e?.status===window.Office.AsyncResultStatus.Succeeded?(Tn=!0,Er("Live")):(Er("Manual"),pr("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene."))}),window.addEventListener("beforeunload",Jo)}catch(e){console.warn("Unable to register Word selection tracking handler.",e),Er("Manual"),pr("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.")}}})():(pr("Word document access is unavailable."),Er("Manual"))}).catch(e=>{console.error("Office readiness check failed.",e),dr("Unable to connect to PlotDirector."),cr("Word Companion unavailable"),pr("Word document access is unavailable."),aa({ready:"No",wordApi:"No",lastScan:"Failure"})})})(); \ No newline at end of file