@model ImportIndexViewModel
@{
    ViewData["Title"] = "JSON Import";
    var preview = Model.Preview;
}

<div class="page-heading compact">
    <div>
        <p class="eyebrow">Tools</p>
        <h1>JSON Import <help-icon key="imports.overview" /></h1>
        <p class="lead-text">Paste or upload a legacy JSON package or a PlotDirector backup file, preview it, dry-run if needed, then import a new project.</p>
    </div>
    <div class="button-row">
        <a class="btn btn-outline-primary" asp-action="Sample">Download sample JSON</a>
        <a class="btn btn-outline-secondary" asp-controller="Projects" asp-action="Index">Back to projects</a>
    </div>
</div>

@if (!string.IsNullOrWhiteSpace(Model.StatusMessage))
{
    <div class="alert alert-warning">
        <strong>Import paused</strong>
        <p class="mb-0">@Model.StatusMessage</p>
        @if (preview is { Package: not null, HasDuplicateProjectTitle: true })
        {
            <p class="mb-0 mt-2">Duplicate imports will be renamed to <strong>@preview.DuplicateImportProjectTitle</strong>.</p>
        }
        @if (!string.IsNullOrWhiteSpace(Model.TechnicalDetail))
        {
            <details class="mt-2">
                <summary>Technical detail</summary>
                <p class="mb-0 mt-2">@Model.TechnicalDetail</p>
            </details>
        }
    </div>
}

<section class="edit-panel import-panel">
    <form asp-action="Preview" method="post" enctype="multipart/form-data">
        <div class="row g-3">
            <div class="col-12">
                <label asp-for="JsonFile" class="form-label">Upload JSON or PlotDirector backup file</label>
                <input asp-for="JsonFile" class="form-control" type="file" accept=".json,.plotdirector,application/json" />
                <div class="form-text">Uploading a file replaces the pasted text for this preview.</div>
                <div class="form-text" data-upload-status></div>
            </div>
            <div class="col-12">
                <label asp-for="JsonText" class="form-label">JSON package or backup content</label>
                <textarea asp-for="JsonText" class="form-control import-json-input" rows="22" spellcheck="false"></textarea>
            </div>
        </div>
        <div class="button-row mt-3">
            <button class="btn btn-primary" type="submit">Validate and preview</button>
            <button class="btn btn-outline-secondary" type="button" data-copy-sample>Use sample JSON</button>
        </div>
    </form>
</section>

<section class="list-section import-docs mt-3">
    <details>
        <summary>Supported JSON schema</summary>
        <div class="import-doc-grid">
            <div>
                <h3>Required</h3>
                <p><code>project.title</code>, each <code>book.title</code>, each <code>book.seriesOrder</code>, each <code>chapter.title</code>, each <code>chapter.order</code>, each <code>scene.title</code>, and each <code>scene.order</code>.</p>
            </div>
            <div>
                <h3>Optional</h3>
                <p><code>packageVersion</code>, <code>source</code>, <code>createdBy</code>, <code>createdDate</code>, <code>description</code>, top-level <code>aliases</code>, top-level <code>characters</code>, top-level <code>locations</code>, top-level <code>plotLines</code>, top-level <code>storyAssets</code>, top-level <code>sceneDependencies</code>, plot line <code>threads</code>, thread <code>events</code>, asset <code>states</code>, asset <code>events</code>, initial asset owner/location mapping, POV/location mapping, date/time text, purpose/outcome text, and <code>sceneCharacters</code>.</p>
            </div>
            <div>
                <h3>Dry run and aliases</h3>
                <p>Dry run performs validation and mapping diagnostics without saving data. <code>aliases.characters</code> and <code>aliases.locations</code> map imported names to top-level names before matching. Matching is case-insensitive, trims whitespace, normalizes repeated spaces, and uses punctuation-insensitive matching only when safe.</p>
            </div>
            <div>
                <h3>Scene links</h3>
                <p><code>sceneDependencies</code> use <code>fromScene</code> and <code>toScene</code> objects. Link scenes with <code>bookOrder</code>, <code>chapterOrder</code>, and <code>sceneOrder</code>; <code>sceneRef</code> is optional future-friendly text. <code>dependencyType</code>, <code>strength</code>, <code>description</code>, and <code>notes</code> are optional. Warnings can be acknowledged; errors block import. Unknown fields are ignored safely.</p>
            </div>
            <div>
                <h3>Not imported yet</h3>
                <p>No AI extraction, Word/text parsing, manuscript parsing, metrics import, continuity warning import, relationship graphs, merge/update, or export logic. This importer is ready for manuscript-derived JSON, and unknown fields are ignored safely.</p>
            </div>
        </div>
    </details>
</section>

@if (preview is not null)
{
    <section class="list-section import-preview-section mt-3">
        <div class="import-preview-heading">
            <div>
                <p class="eyebrow">Preview</p>
                <h2>@(preview.Package?.Project.Title ?? "Import package")</h2>
            </div>
            <div class="import-counts">
                <span><strong>@preview.BookCount</strong> books</span>
                <span><strong>@preview.ChapterCount</strong> chapters</span>
                <span><strong>@preview.SceneCount</strong> scenes</span>
                <span><strong>@preview.CharacterCount</strong> characters</span>
                <span><strong>@preview.LocationCount</strong> locations</span>
                <span><strong>@preview.SceneCharacterAppearanceCount</strong> appearances</span>
                <span><strong>@preview.PlotLineCount</strong> plot lines</span>
                <span><strong>@preview.PlotThreadCount</strong> threads</span>
                <span><strong>@preview.ResolvedThreadEventCount</strong> events</span>
                <span><strong>@preview.StoryAssetCount</strong> assets</span>
                <span><strong>@preview.ResolvedAssetStateCount</strong> asset states</span>
                <span><strong>@preview.ResolvedAssetEventCount</strong> asset events</span>
                <span><strong>@preview.ResolvedAssetCustodyCount</strong> custody links</span>
                <span><strong>@preview.ResolvedSceneDependencyCount</strong> dependencies</span>
                <span><strong>@preview.ErrorCount</strong> errors</span>
                <span><strong>@preview.WarningCount</strong> warnings</span>
                <span><strong>@preview.UnresolvedReferenceCount</strong> unresolved</span>
                <span><strong>@preview.AutoCorrectionCount</strong> corrections</span>
                <span><strong>@preview.SkippedItemCount</strong> skipped</span>
            </div>
        </div>

        <div class="alert alert-light import-message-list">
            <strong>Import health</strong>
            <div class="import-counts mt-2">
                <span><strong>@preview.ErrorCount</strong> errors</span>
                <span><strong>@preview.WarningCount</strong> warnings</span>
                <span><strong>@preview.AutoCorrectionCount</strong> auto-corrections</span>
                <span><strong>@preview.SkippedItemCount</strong> skipped items</span>
                <span><strong>@preview.UnresolvedReferenceCount</strong> unresolved references</span>
            </div>
            @if (preview.Package is not null && (!string.IsNullOrWhiteSpace(preview.Package.Source) || !string.IsNullOrWhiteSpace(preview.Package.CreatedBy) || !string.IsNullOrWhiteSpace(preview.Package.CreatedDate) || !string.IsNullOrWhiteSpace(preview.Package.Description)))
            {
                <p class="muted mt-2 mb-0">
                    Source: @(preview.Package.Source ?? "Not supplied") /
                    Created by: @(preview.Package.CreatedBy ?? "Not supplied") /
                    Created date: @(preview.Package.CreatedDate ?? "Not supplied")
                    @if (!string.IsNullOrWhiteSpace(preview.Package.Description))
                    {
                        <span>/ @preview.Package.Description</span>
                    }
                </p>
            }
        </div>

        <div class="button-row mb-3">
            <form asp-action="ValidationReport" method="post">
                @* Carry forward the active textarea JSON for secondary forms. The visible textarea is authoritative. *@
                <input name="JsonText" type="hidden" value="@Model.JsonText" data-json-carry-forward />
                <button class="btn btn-outline-secondary btn-sm" type="submit">Download validation report</button>
            </form>
        </div>

        @if (preview.Validation.Errors.Any())
        {
            <div class="alert alert-warning import-message-list">
                <strong>Errors block import</strong>
                <ul class="mb-0 mt-2">
                    @foreach (var error in preview.Validation.Errors)
                    {
                        <li>@error</li>
                    }
                </ul>
            </div>
        }

        @if (preview.Validation.Warnings.Any())
        {
            <div class="alert alert-info import-message-list">
                <strong>Warnings require confirmation</strong>
                <ul class="mb-0 mt-2">
                    @foreach (var warning in preview.Validation.Warnings)
                    {
                        <li>@warning</li>
                    }
                </ul>
            </div>
        }

        @if (preview.AutoCorrections.Any() || preview.Validation.AutoCorrections.Any() || preview.SkippedItems.Any() || preview.Validation.SkippedItems.Any() || preview.AliasWarnings.Any())
        {
            <details class="import-mapping-summary" open>
                <summary>Health details</summary>
                @if (preview.AutoCorrections.Any() || preview.Validation.AutoCorrections.Any())
                {
                    <span>Auto-corrections: @string.Join("; ", preview.AutoCorrections.Concat(preview.Validation.AutoCorrections).Take(12))</span>
                }
                @if (preview.SkippedItems.Any() || preview.Validation.SkippedItems.Any())
                {
                    <span>Skipped items: @string.Join("; ", preview.SkippedItems.Concat(preview.Validation.SkippedItems).Take(12))</span>
                }
                @if (preview.AliasWarnings.Any())
                {
                    <span>Alias warnings: @string.Join("; ", preview.AliasWarnings.Take(12))</span>
                }
            </details>
        }

        @if (preview.Package is not null)
        {
            @if (preview.UnmatchedPovNames.Any() || preview.UnmatchedLocationNames.Any() || preview.UnmatchedSceneCharacterNames.Any() || preview.UnresolvedThreadEventReferences.Any() || preview.UnresolvedAssetReferences.Any() || preview.UnmatchedAssetOwnerNames.Any() || preview.UnmatchedAssetLocationNames.Any() || preview.UnresolvedSceneDependencyReferences.Any())
            {
                <div class="import-mapping-summary">
                    @if (preview.UnmatchedPovNames.Any())
                    {
                        <span>Unmatched POV: @string.Join(", ", preview.UnmatchedPovNames)</span>
                    }
                    @if (preview.UnmatchedLocationNames.Any())
                    {
                        <span>Unmatched locations: @string.Join(", ", preview.UnmatchedLocationNames)</span>
                    }
                    @if (preview.UnmatchedSceneCharacterNames.Any())
                    {
                        <span>Unmatched scene characters: @string.Join(", ", preview.UnmatchedSceneCharacterNames)</span>
                    }
                    @if (preview.UnresolvedThreadEventReferences.Any())
                    {
                        <span>Unresolved thread events: @string.Join(", ", preview.UnresolvedThreadEventReferences)</span>
                    }
                    @if (preview.UnresolvedAssetReferences.Any())
                    {
                        <span>Unresolved asset references: @string.Join(", ", preview.UnresolvedAssetReferences)</span>
                    }
                    @if (preview.UnmatchedAssetOwnerNames.Any())
                    {
                        <span>Unmatched asset owners/events: @string.Join(", ", preview.UnmatchedAssetOwnerNames)</span>
                    }
                    @if (preview.UnmatchedAssetLocationNames.Any())
                    {
                        <span>Unmatched asset locations: @string.Join(", ", preview.UnmatchedAssetLocationNames)</span>
                    }
                    @if (preview.UnresolvedSceneDependencyReferences.Any())
                    {
                        <span>Unresolved dependencies: @string.Join(", ", preview.UnresolvedSceneDependencyReferences)</span>
                    }
                </div>
            }

            <div class="import-tree">
                @foreach (var bookPreview in preview.BookPreviews)
                {
                    var book = bookPreview.Book;
                    <details class="import-tree-book" @(preview.BookCount <= 4 ? "open" : "")>
                        <summary>
                            <strong>Book @book.SeriesOrder: @(string.IsNullOrWhiteSpace(book.Subtitle) ? book.Title : $"{book.Title}: {book.Subtitle}")</strong>
                            <span>@bookPreview.ChapterCount chapters / @bookPreview.SceneCount scenes</span>
                        </summary>
                        @foreach (var chapterPreview in bookPreview.ChapterPreviews)
                        {
                            var chapter = chapterPreview.Chapter;
                            <details class="import-tree-chapter">
                                <summary>
                                    <strong>Chapter @chapter.ChapterNumber: @chapter.Title</strong>
                                    <span>@chapterPreview.SceneCount scenes</span>
                                </summary>
                                <ul>
                                    @foreach (var scene in chapter.Scenes.OrderBy(x => x.Order))
                                    {
                                        <li>
                                            <strong>Scene @scene.SceneNumber: @scene.Title</strong>
                                            <span class="import-scene-meta">
                                                POV: @(scene.PovCharacterName ?? "Not set") /
                                                Location: @(scene.LocationName ?? "Not set") /
                                                Characters: @scene.SceneCharacters.Count
                                            </span>
                                        </li>
                                    }
                                </ul>
                            </details>
                        }
                    </details>
                }
            </div>

            @if (preview.Package.PlotLines.Any())
            {
                <div class="import-tree mt-3">
                    @foreach (var plotLine in preview.Package.PlotLines)
                    {
                        <details class="import-tree-book">
                            <summary>
                                <strong>Plot line: @(string.IsNullOrWhiteSpace(plotLine.DisplayName) ? plotLine.Name : plotLine.DisplayName)</strong>
                                <span>@plotLine.Threads.Count threads / @plotLine.Threads.Sum(x => x.Events.Count) events</span>
                            </summary>
                            @foreach (var thread in plotLine.Threads)
                            {
                                <details class="import-tree-chapter">
                                    <summary>
                                        <strong>@(string.IsNullOrWhiteSpace(thread.DisplayName) ? thread.Name : thread.DisplayName)</strong>
                                        <span>@thread.Events.Count events</span>
                                    </summary>
                                </details>
                            }
                        </details>
                    }
                </div>
            }

            @if (preview.Package.SceneDependencies.Any())
            {
                <div class="import-tree mt-3">
                    @foreach (var group in preview.Package.SceneDependencies.Select((dependency, index) => new { Dependency = dependency, Index = index + 1 }).GroupBy(x => $"{x.Dependency.FromScene?.BookOrder?.ToString() ?? "?"}/{x.Dependency.FromScene?.ChapterOrder?.ToString() ?? "?"}").OrderBy(x => x.Key))
                    {
                        <details class="import-tree-book">
                            <summary>
                                <strong>Dependencies from @group.Key</strong>
                                <span>@group.Count() links</span>
                            </summary>
                            <ul>
                                @foreach (var item in group.Take(12))
                                {
                                    var dependency = item.Dependency;
                                    var fromScene = $"{dependency.FromScene?.BookOrder?.ToString() ?? "?"}/{dependency.FromScene?.ChapterOrder?.ToString() ?? "?"}/{dependency.FromScene?.SceneOrder?.ToString() ?? "?"}";
                                    var toScene = $"{dependency.ToScene?.BookOrder?.ToString() ?? "?"}/{dependency.ToScene?.ChapterOrder?.ToString() ?? "?"}/{dependency.ToScene?.SceneOrder?.ToString() ?? "?"}";
                                    <li>
                                        <strong>@fromScene -> @toScene</strong>
                                        <span class="import-scene-meta">@((dependency.DependencyType ?? "Dependency")) / @(dependency.Strength ?? "soft")</span>
                                    </li>
                                }
                                @if (group.Count() > 12)
                                {
                                    <li class="muted">Showing first 12 links in this group.</li>
                                }
                            </ul>
                        </details>
                    }
                </div>
            }

            @if (preview.Package.StoryAssets.Any())
            {
                <div class="import-tree mt-3">
                    @foreach (var asset in preview.Package.StoryAssets)
                    {
                        <details class="import-tree-book">
                            <summary>
                                <strong>Asset: @(string.IsNullOrWhiteSpace(asset.DisplayName) ? asset.Name : asset.DisplayName)</strong>
                                <span>@asset.States.Count states / @asset.Events.Count events</span>
                            </summary>
                            <ul>
                                <li>Type: @(asset.Type ?? "Not set") / Initial owner: @(asset.InitialOwnerCharacterName ?? "Not set") / Initial location: @(asset.InitialLocationName ?? "Not set")</li>
                            </ul>
                        </details>
                    }
                </div>
            }

            <section class="import-confirmation mt-3">
                <h3>Confirm import</h3>
                <p>This will create <strong>@preview.Package.Project.Title</strong> with <strong>@preview.BookCount</strong> books, <strong>@preview.ChapterCount</strong> chapters, <strong>@preview.SceneCount</strong> scenes, <strong>@preview.CharacterCount</strong> characters, <strong>@preview.LocationCount</strong> locations, <strong>@preview.SceneCharacterAppearanceCount</strong> scene character appearances, <strong>@preview.PlotLineCount</strong> plot lines, <strong>@preview.PlotThreadCount</strong> plot threads, <strong>@preview.ResolvedThreadEventCount</strong> resolved thread events, <strong>@preview.StoryAssetCount</strong> story assets, <strong>@preview.ResolvedAssetStateCount</strong> resolved asset states, <strong>@preview.ResolvedAssetEventCount</strong> resolved asset events, <strong>@preview.ResolvedAssetCustodyCount</strong> custody links, and <strong>@preview.ResolvedSceneDependencyCount</strong> scene dependencies.</p>
                @if (preview.HasDuplicateProjectTitle)
                {
                    <p class="muted">Because this title already exists, the created project will be named <strong>@preview.DuplicateImportProjectTitle</strong> if you continue.</p>
                }

                <form asp-action="Import" method="post" class="import-confirm-form">
                    @* Carry forward the active textarea JSON for dry run/import. The visible textarea is authoritative. *@
                    <input name="JsonText" type="hidden" value="@Model.JsonText" data-json-carry-forward />
                    @if (preview.Validation.Warnings.Any())
                    {
                        <div class="form-check import-duplicate-confirm">
                            <input asp-for="AcknowledgeWarnings" class="form-check-input" />
                            <label asp-for="AcknowledgeWarnings" class="form-check-label">I have reviewed the warnings and still want to import this package.</label>
                        </div>
                    }
                    @if (preview.HasDuplicateProjectTitle)
                    {
                        <div class="form-check import-duplicate-confirm mt-2">
                            <input asp-for="AllowDuplicateProjectTitle" class="form-check-input" />
                            <label asp-for="AllowDuplicateProjectTitle" class="form-check-label">
                                Import anyway using the renamed project title shown above.
                            </label>
                        </div>
                    }
                    <div class="form-check import-duplicate-confirm mt-2">
                        <input asp-for="ConfirmImport" class="form-check-input" />
                        <label asp-for="ConfirmImport" class="form-check-label">I understand this will create new records in PlotDirector.</label>
                    </div>
                    <div class="form-check import-duplicate-confirm mt-2">
                        <input asp-for="DryRun" class="form-check-input" />
                        <label asp-for="DryRun" class="form-check-label">Dry run only. Validate and simulate counts without saving data.</label>
                    </div>
                    <button class="btn btn-primary mt-3" type="submit" disabled="@(!preview.Validation.IsValid)">Import or dry run</button>
                </form>
            </section>
        }
    </section>
}

<script type="application/json" id="importSampleJson">@Html.Raw(System.Text.Json.JsonSerializer.Serialize(ImportIndexViewModel.SampleJson))</script>

@section Scripts {
    <script>
        (() => {
            const button = document.querySelector("[data-copy-sample]");
            const textarea = document.querySelector("#JsonText");
            const sample = document.querySelector("#importSampleJson");
            const fileInput = document.querySelector("#JsonFile");
            const uploadStatus = document.querySelector("[data-upload-status]");
            const syncHiddenJson = () => {
                document.querySelectorAll("[data-json-carry-forward]").forEach((input) => {
                    input.value = textarea?.value || "";
                });
            };

            if (button && textarea && sample) {
                button.addEventListener("click", () => {
                    textarea.value = JSON.parse(sample.textContent);
                    syncHiddenJson();
                    if (uploadStatus) uploadStatus.textContent = "Sample JSON loaded into the package textarea.";
                    textarea.focus();
                });
            }

            fileInput?.addEventListener("change", () => {
                const file = fileInput.files && fileInput.files[0];
                if (!file || !textarea) return;

                if (file.size === 0) {
                    if (uploadStatus) uploadStatus.textContent = `${file.name} is empty. Choose a JSON file with content.`;
                    fileInput.value = "";
                    return;
                }

                const reader = new FileReader();
                reader.onload = () => {
                    textarea.value = reader.result || "";
                    syncHiddenJson();
                    if (uploadStatus) uploadStatus.textContent = `Loaded JSON from ${file.name}.`;
                };
                reader.onerror = () => {
                    if (uploadStatus) uploadStatus.textContent = `Could not read ${file.name}. Try choosing the file again.`;
                    fileInput.value = "";
                };
                reader.readAsText(file, "UTF-8");
            });

            textarea?.addEventListener("input", syncHiddenJson);
            document.querySelectorAll("form").forEach((form) => {
                form.addEventListener("submit", syncHiddenJson);
            });
        })();
    </script>
}
