@model StoryIntelligenceDryRunViewModel
@{
    ViewData["Title"] = "Story Intelligence Dry Run";
    var result = Model.Result;
}

<div class="page-heading compact">
    <div>
        <p class="eyebrow">Admin utility</p>
        <h1>Story Intelligence Dry Run</h1>
        <p class="lead-text">This is a development dry run. It makes one live OpenAI extraction request only when submitted, and it does not save data or modify projects.</p>
    </div>
</div>

<nav class="mb-3" aria-label="Breadcrumb">
    <a asp-controller="Projects" asp-action="Index">Projects</a>
    <span class="muted"> / </span>
    <a asp-action="Index">Admin</a>
    <span class="muted"> / </span>
    <a asp-action="StoryIntelligenceDiagnostics">Story Intelligence Diagnostics</a>
    <span class="muted"> / Dry Run</span>
</nav>

<section class="edit-panel">
    <h2>Manual scene test</h2>
    <p>Use short fictional sample text only. This page loads <code>Scene-Prompt-V2.md</code>, replaces runtime placeholders, makes a live extraction request when submitted, and displays the raw response without parsing or saving it.</p>
    <form asp-action="StoryIntelligenceTest" method="post">
        <div class="row g-3">
            <div class="col-md-3">
                <label class="form-label" asp-for="Form.ProjectID">ProjectID</label>
                <input class="form-control" asp-for="Form.ProjectID" />
            </div>
            <div class="col-md-3">
                <label class="form-label" asp-for="Form.BookID">BookID</label>
                <input class="form-control" asp-for="Form.BookID" />
            </div>
            <div class="col-md-3">
                <label class="form-label" asp-for="Form.ChapterID">ChapterID</label>
                <input class="form-control" asp-for="Form.ChapterID" />
            </div>
            <div class="col-md-3">
                <label class="form-label" asp-for="Form.SceneID">SceneID</label>
                <input class="form-control" asp-for="Form.SceneID" />
            </div>
            <div class="col-md-3">
                <label class="form-label" asp-for="Form.ChapterNumber">ChapterNumber</label>
                <input class="form-control" asp-for="Form.ChapterNumber" />
            </div>
            <div class="col-md-3">
                <label class="form-label" asp-for="Form.SceneNumber">SceneNumber</label>
                <input class="form-control" asp-for="Form.SceneNumber" />
            </div>
            <div class="col-md-6">
                <label class="form-label" asp-for="Form.SourceLabel">SourceLabel</label>
                <input class="form-control" asp-for="Form.SourceLabel" />
            </div>
            <div class="col-12">
                <label class="form-label" asp-for="Form.SceneText">Scene text</label>
                <textarea class="form-control" asp-for="Form.SceneText" rows="8"></textarea>
            </div>
        </div>
        <div class="button-row mt-3">
            <button class="btn btn-primary" type="submit">Run dry test</button>
            <a class="btn btn-outline-secondary" asp-action="StoryIntelligenceDiagnostics">Back to diagnostics</a>
        </div>
    </form>
</section>

@if (result is not null)
{
    <section class="edit-panel">
        <h2>Dry-run result</h2>
        @if (!result.Success)
        {
            <div class="alert alert-warning">@result.ErrorMessage</div>
        }
        <div class="row g-3">
            <div class="col-md-3">
                <div class="border rounded p-3 h-100">
                    <p class="eyebrow">Prompt version</p>
                    <h3 class="mb-0">@result.PromptVersion</h3>
                </div>
            </div>
            <div class="col-md-3">
                <div class="border rounded p-3 h-100">
                    <p class="eyebrow">Model</p>
                    <h3 class="mb-0">@result.Model</h3>
                </div>
            </div>
            <div class="col-md-3">
                <div class="border rounded p-3 h-100">
                    <p class="eyebrow">Duration</p>
                    <h3 class="mb-0">@(string.IsNullOrWhiteSpace(result.Duration) ? "Not run" : result.Duration)</h3>
                </div>
            </div>
            <div class="col-md-3">
                <div class="border rounded p-3 h-100">
                    <p class="eyebrow">Retries</p>
                    <h3 class="mb-0">@result.RetryCount.ToString("N0")</h3>
                </div>
            </div>
        </div>
        <div class="mt-3">
            <dl class="mb-0">
                <dt>Input tokens</dt>
                <dd>@(result.InputTokens.HasValue ? result.InputTokens.Value.ToString("N0") : "Not reported")</dd>
                <dt>Output tokens</dt>
                <dd>@(result.OutputTokens.HasValue ? result.OutputTokens.Value.ToString("N0") : "Not reported")</dd>
            </dl>
        </div>

        <ul class="nav nav-tabs mt-4" id="storyIntelligenceTabs" role="tablist">
            <li class="nav-item" role="presentation">
                <button class="nav-link active" id="raw-response-tab" data-bs-toggle="tab" data-bs-target="#raw-response" type="button" role="tab" aria-controls="raw-response" aria-selected="true">Raw Response</button>
            </li>
            <li class="nav-item" role="presentation">
                <button class="nav-link" id="validation-tab" data-bs-toggle="tab" data-bs-target="#validation" type="button" role="tab" aria-controls="validation" aria-selected="false">Validation</button>
            </li>
            <li class="nav-item" role="presentation">
                <button class="nav-link" id="parsed-model-tab" data-bs-toggle="tab" data-bs-target="#parsed-model" type="button" role="tab" aria-controls="parsed-model" aria-selected="false">Parsed Model</button>
            </li>
        </ul>

        <div class="tab-content border border-top-0 rounded-bottom p-3" id="storyIntelligenceTabContent">
            <div class="tab-pane fade show active" id="raw-response" role="tabpanel" aria-labelledby="raw-response-tab" tabindex="0">
                <div class="mb-3">
                    <label class="form-label" for="sceneContextJson">Scene context JSON</label>
                    <textarea class="form-control font-monospace" id="sceneContextJson" rows="8" readonly>@result.SceneContextJson</textarea>
                </div>
                @if (!string.IsNullOrWhiteSpace(result.SceneJsonText))
                {
                    <div class="mb-3">
                        <label class="form-label" for="sceneJsonText">Extracted Scene Intelligence JSON</label>
                        <textarea class="form-control font-monospace" id="sceneJsonText" rows="12" readonly>@result.SceneJsonText</textarea>
                    </div>
                }
                <div>
                    <label class="form-label" for="rawResponseText">Raw OpenAI response</label>
                    <textarea class="form-control font-monospace" id="rawResponseText" rows="18" readonly>@result.RawResponseText</textarea>
                </div>
            </div>

            <div class="tab-pane fade" id="validation" role="tabpanel" aria-labelledby="validation-tab" tabindex="0">
                @if (result.Validation is null)
                {
                    <div class="alert alert-warning">Validation did not run.</div>
                }
                else
                {
                    <h3>@ValidationSummary(result.Validation)</h3>
                    @RenderIssues("Errors", result.Validation.Errors)
                    @RenderIssues("Warnings", result.Validation.Warnings)
                    @RenderIssues("Information", result.Validation.Information)
                }
            </div>

            <div class="tab-pane fade" id="parsed-model" role="tabpanel" aria-labelledby="parsed-model-tab" tabindex="0">
                @if (result.ParsedScene is null)
                {
                    <div class="alert alert-warning">No parsed Scene Intelligence model is available.</div>
                }
                else
                {
                    var scene = result.ParsedScene;
                    <div class="row g-3">
                        <div class="col-lg-6">
                            <section class="border rounded p-3 h-100">
                                <h3>Scene Reference</h3>
                                <dl class="mb-0">
                                    <dt>Schema</dt>
                                    <dd>@scene.SchemaVersion</dd>
                                    <dt>Project</dt>
                                    <dd>@Display(scene.SceneReference?.ProjectId)</dd>
                                    <dt>Book</dt>
                                    <dd>@Display(scene.SceneReference?.BookId)</dd>
                                    <dt>Chapter</dt>
                                    <dd>@Display(scene.SceneReference?.ChapterId) (@Display(scene.SceneReference?.ChapterNumber))</dd>
                                    <dt>Scene</dt>
                                    <dd>@Display(scene.SceneReference?.SceneId) (@Display(scene.SceneReference?.SceneNumber))</dd>
                                    <dt>Source</dt>
                                    <dd>@Display(scene.SceneReference?.SourceLabel)</dd>
                                </dl>
                            </section>
                        </div>
                        <div class="col-lg-6">
                            <section class="border rounded p-3 h-100">
                                <h3>Summary</h3>
                                <p><strong>Short:</strong> @Display(scene.Summary?.Short)</p>
                                <p><strong>Detailed:</strong> @Display(scene.Summary?.Detailed)</p>
                                <p class="mb-0"><strong>Confidence:</strong> @Display(scene.Summary?.Confidence)</p>
                            </section>
                        </div>
                    </div>

                    <div class="row g-3 mt-1">
                        <div class="col-lg-4">
                            <section class="border rounded p-3 h-100">
                                <h3>Purpose</h3>
                                <p>@Display(scene.ScenePurpose?.ObservedFunction)</p>
                                <p class="mb-0"><strong>Confidence:</strong> @Display(scene.ScenePurpose?.Confidence)</p>
                            </section>
                        </div>
                        <div class="col-lg-4">
                            <section class="border rounded p-3 h-100">
                                <h3>Point Of View</h3>
                                <dl class="mb-0">
                                    <dt>Character</dt>
                                    <dd>@Display(scene.PointOfView?.CharacterName)</dd>
                                    <dt>Mode</dt>
                                    <dd>@Display(scene.PointOfView?.NarrativeMode)</dd>
                                    <dt>Evidence</dt>
                                    <dd>@Display(scene.PointOfView?.Evidence)</dd>
                                    <dt>Confidence</dt>
                                    <dd>@Display(scene.PointOfView?.Confidence)</dd>
                                </dl>
                            </section>
                        </div>
                        <div class="col-lg-4">
                            <section class="border rounded p-3 h-100">
                                <h3>Setting</h3>
                                <dl class="mb-0">
                                    <dt>Location</dt>
                                    <dd>@Display(scene.Setting?.LocationName)</dd>
                                    <dt>Type</dt>
                                    <dd>@Display(scene.Setting?.LocationType)</dd>
                                    <dt>Room</dt>
                                    <dd>@Display(scene.Setting?.GenericRoomType)</dd>
                                    <dt>Time</dt>
                                    <dd>@Display(scene.Setting?.TimeOfDay) / @Display(scene.Setting?.DateOrTimeReference)</dd>
                                    <dt>Confidence</dt>
                                    <dd>@Display(scene.Setting?.Confidence)</dd>
                                </dl>
                            </section>
                        </div>
                    </div>

                    @RenderCollection("Characters", scene.Characters, character =>
                        $"{Display(character.Name)} - {Display(character.RoleInScene)} - mentioned only: {Display(character.MentionedOnly)} - confidence: {Display(character.Confidence)}")
                    @RenderCollection("Locations", scene.Locations, location =>
                        $"{Display(location.Name)} - {Display(location.LocationType)} - present: {Display(location.PresentInScene)} - confidence: {Display(location.Confidence)}")
                    @RenderCollection("Assets", scene.Assets, asset =>
                        $"{Display(asset.Name)} - {Display(asset.AssetType)} - status: {Display(asset.Status)} - holder: {Display(asset.OwnerOrHolder)}")
                    @RenderCollection("Relationships", scene.Relationships, relationship =>
                        $"{Display(relationship.CharacterA)} / {Display(relationship.CharacterB)} - {Display(relationship.RelationshipSignal)} - confidence: {Display(relationship.Confidence)}")
                    @RenderCollection("Knowledge Changes", scene.KnowledgeChanges, change =>
                        $"{Display(change.RecipientCharacter)} {Display(change.ChangeType)}: {Display(change.KnowledgeItem)}")
                    @RenderCollection("Timeline Clues", scene.TimelineClues, clue =>
                        $"{Display(clue.Clue)} - {Display(clue.RelativeOrder)}")
                    @RenderCollection("Questions Raised", scene.QuestionsRaised, question =>
                        $"{Display(question.Question)} - {Display(question.Scope)}")
                    @RenderCollection("Questions Answered", scene.QuestionsAnswered, answer =>
                        $"{Display(answer.Question)} => {Display(answer.Answer)}")
                    @RenderCollection("Observations", scene.Observations, observation =>
                        $"{Display(observation.SubjectName)} {Display(observation.Predicate)} {Display(observation.ObjectName)} - {Display(observation.ObservationType)}")

                    <section class="border rounded p-3 mt-3">
                        <h3>Metrics</h3>
                        @if (scene.Metrics is null || scene.Metrics.Count == 0)
                        {
                            <p class="mb-0">No metrics reported.</p>
                        }
                        else
                        {
                            <dl class="mb-0">
                                @foreach (var metric in scene.Metrics)
                                {
                                    <dt>@metric.Key</dt>
                                    <dd>Score @Display(metric.Value?.Score), confidence @Display(metric.Value?.Confidence)</dd>
                                }
                            </dl>
                        }
                    </section>

                    <section class="border rounded p-3 mt-3">
                        <h3>Source Limits</h3>
                        <p><strong>Contains ambiguity:</strong> @Display(scene.SourceLimits?.ContainsAmbiguity)</p>
                        @RenderStringList("Ambiguity Notes", scene.SourceLimits?.AmbiguityNotes)
                    </section>
                }
            </div>
        </div>
    </section>
}

@functions {
    private static string Display(object? value) => value switch
    {
        null => "None",
        string text when string.IsNullOrWhiteSpace(text) => "None",
        decimal number => number.ToString("0.##"),
        bool flag => flag ? "Yes" : "No",
        _ => value.ToString() ?? "None"
    };

    private static string ValidationSummary(PlotLine.Models.StoryIntelligence.ValidationResult validation)
        => validation.IsValid
            ? $"✓ Passed with {validation.Warnings.Count:N0} warning(s)"
            : $"✖ Failed with {validation.Errors.Count:N0} error(s) and {validation.Warnings.Count:N0} warning(s)";

    private static string SeveritySymbol(string severity) => severity switch
    {
        "Error" => "✖",
        "Warning" => "⚠",
        _ => "✓"
    };

    private static Microsoft.AspNetCore.Html.IHtmlContent RenderIssues(string heading, IReadOnlyList<PlotLine.Models.StoryIntelligence.ValidationIssue> issues)
    {
        var builder = new System.Text.StringBuilder();
        builder.Append("<section class=\"mt-3\">");
        builder.Append("<h4>").Append(Encode(heading)).Append(" (").Append(issues.Count.ToString("N0")).Append(")</h4>");
        if (issues.Count == 0)
        {
            builder.Append("<p class=\"mb-0\">None.</p>");
        }
        else
        {
            builder.Append("<div class=\"list-group\">");
            foreach (var issue in issues)
            {
                builder.Append("<div class=\"list-group-item\">");
                builder.Append("<p class=\"mb-1\"><strong>")
                    .Append(Encode(SeveritySymbol(issue.Severity)))
                    .Append(' ')
                    .Append(Encode(issue.Severity))
                    .Append("</strong> <code>")
                    .Append(Encode(issue.Path))
                    .Append("</code></p>");
                builder.Append("<p class=\"mb-1\">").Append(Encode(issue.Message)).Append("</p>");
                builder.Append("<p class=\"mb-0 muted\">").Append(Encode(issue.SuggestedFix)).Append("</p>");
                builder.Append("</div>");
            }

            builder.Append("</div>");
        }

        builder.Append("</section>");
        return new Microsoft.AspNetCore.Html.HtmlString(builder.ToString());
    }

    private static Microsoft.AspNetCore.Html.IHtmlContent RenderCollection<T>(string heading, IReadOnlyList<T>? items, Func<T, string> formatter)
    {
        var builder = new System.Text.StringBuilder();
        builder.Append("<section class=\"border rounded p-3 mt-3\">");
        builder.Append("<h3>").Append(Encode(heading)).Append("</h3>");
        if (items is null || items.Count == 0)
        {
            builder.Append("<p class=\"mb-0\">No items reported.</p>");
        }
        else
        {
            builder.Append("<ol class=\"mb-0\">");
            foreach (var item in items)
            {
                builder.Append("<li>").Append(Encode(formatter(item))).Append("</li>");
            }

            builder.Append("</ol>");
        }

        builder.Append("</section>");
        return new Microsoft.AspNetCore.Html.HtmlString(builder.ToString());
    }

    private static Microsoft.AspNetCore.Html.IHtmlContent RenderStringList(string heading, IReadOnlyList<string>? items)
    {
        var builder = new System.Text.StringBuilder();
        builder.Append("<h4>").Append(Encode(heading)).Append("</h4>");
        if (items is null || items.Count == 0)
        {
            builder.Append("<p class=\"mb-0\">No items reported.</p>");
        }
        else
        {
            builder.Append("<ul class=\"mb-0\">");
            foreach (var item in items)
            {
                builder.Append("<li>").Append(Encode(item)).Append("</li>");
            }

            builder.Append("</ul>");
        }

        return new Microsoft.AspNetCore.Html.HtmlString(builder.ToString());
    }

    private static string Encode(string? value)
        => System.Net.WebUtility.HtmlEncode(value ?? string.Empty);
}
