@using System.Text.Json
@model RelationshipMapViewModel
@{
    ViewData["Title"] = $"Relationship Map - {Model.Project.ProjectName}";
    var jsonOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
}

<nav class="breadcrumb-trail" aria-label="Breadcrumb">
    <a asp-controller="Projects" asp-action="Index">Projects</a>
    <a asp-controller="Projects" asp-action="Details" asp-route-id="@Model.Project.ProjectID">@Model.Project.ProjectName</a>
    <span>Relationship Map</span>
</nav>

<section class="context-header">
    <div class="context-title">
        <span class="eyebrow">Project workspace</span>
        <strong>@Model.Project.ProjectName</strong>
    </div>
    <nav class="context-nav" aria-label="Project navigation">
        <a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Timeline</a>
        <a asp-controller="StoryBible" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Story Bible</a>
        <a class="active" asp-controller="RelationshipMap" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Relationship Map</a>
        <a asp-controller="Characters" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Characters</a>
    </nav>
</section>

<div class="page-heading">
    <div>
        <p class="eyebrow">Relationships</p>
        <h1>Relationship Map <help-icon key="relationshipMap.overview" /></h1>
        <p class="lead-text">A read-only network of character relationships as of @Model.StoryPointLabel.</p>
    </div>
    <div class="button-row">
        <a class="btn btn-outline-secondary" asp-controller="StoryBible" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Story Bible</a>
        <a class="btn btn-outline-secondary" asp-controller="Characters" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Characters</a>
    </div>
</div>

<form class="relationship-map-controls plain-card" method="get" asp-action="Index">
    <input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
    <div>
        <label class="form-label" for="bookId">Book</label>
        <select class="form-select form-select-sm" id="bookId" name="bookId" asp-items="Model.BookOptions">
            <option value="">Project Start</option>
        </select>
    </div>
    <div>
        <label class="form-label" for="chapterId">Chapter</label>
        <select class="form-select form-select-sm" id="chapterId" name="chapterId" asp-items="Model.ChapterOptions">
            <option value="">Any chapter</option>
        </select>
    </div>
    <div>
        <label class="form-label" for="sceneId">Scene</label>
        <select class="form-select form-select-sm" id="sceneId" name="sceneId" asp-items="Model.SceneOptions">
            <option value="">Any scene</option>
        </select>
    </div>
    <div>
        <label class="form-label" for="focusCharacterId">Character focus</label>
        <select class="form-select form-select-sm" id="focusCharacterId" name="focusCharacterId" asp-items="Model.CharacterOptions">
            <option value="">Full cast</option>
        </select>
    </div>
    <label class="form-check relationship-map-check">
        <input class="form-check-input" type="checkbox" name="showFullNetwork" value="true" checked="@Model.ShowFullNetwork" />
        <span class="form-check-label">Show full network</span>
    </label>
    <button class="btn btn-primary btn-sm" type="submit">Update Map</button>
    <a class="btn btn-outline-secondary btn-sm" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Project Start</a>
</form>

<section class="relationship-map-legend plain-card" aria-label="Relationship categories">
    <div>
        <p class="eyebrow">Relationship key</p>
        <h2>Category colours</h2>
    </div>
    <div class="relationship-map-legend-grid">
        @foreach (var category in Model.Categories)
        {
            <span class="relationship-map-legend-item @category.CssClass">
                <span class="relationship-map-legend-line" aria-hidden="true"></span>
                <span>@category.CategoryName</span>
            </span>
        }
    </div>
</section>

<section class="relationship-map-workspace">
    <div class="relationship-map-canvas plain-card">
        @if (!Model.Nodes.Any() || !Model.Links.Any())
        {
            <div class="empty-state">
                <h2>No visible relationships at this point</h2>
                <p class="muted">Add initial relationships or relationship events, choose a later story point, or remove the character focus to build the map.</p>
            </div>
        }
        else
        {
            <div class="relationship-map-toolbar" aria-label="Map controls">
                <button class="btn btn-outline-secondary btn-sm" type="button" data-map-fit>Fit</button>
                <button class="btn btn-outline-secondary btn-sm" type="button" data-map-reset>Reset view</button>
            </div>
            <div id="relationshipMapGraph" class="relationship-map-graph" role="img" aria-label="Relationship network"></div>
            <p id="relationshipMapError" class="alert alert-warning d-none mt-3">The relationship map renderer could not load. The relationship list below is still available.</p>
        }
    </div>

    <aside class="relationship-map-details plain-card">
        <p class="eyebrow">Relationship detail</p>
        <div id="relationshipMapEmptyDetail">
            <h2>Select a relationship</h2>
            <p class="muted">Click a connecting line or choose a relationship below to inspect its current state and history.</p>
        </div>
        <div id="relationshipMapDetail" class="d-none">
            <h2 data-map-detail-title></h2>
            <div class="relationship-map-detail-badges">
                <span class="status-pill" data-map-detail-category></span>
                <span class="status-pill" data-map-detail-reciprocal></span>
            </div>
            <dl class="relationship-map-detail-list">
                <dt>Relationship type</dt>
                <dd data-map-detail-type></dd>
                <dt>Initial state</dt>
                <dd data-map-detail-initial></dd>
                <dt>Current state</dt>
                <dd data-map-detail-current></dd>
            </dl>
            <h3>History</h3>
            <ol class="relationship-map-history" data-map-detail-history></ol>
        </div>
    </aside>
</section>

<section class="list-section">
    <h2>Visible relationships</h2>
    @if (!Model.Relationships.Any())
    {
        <p class="muted">No relationships are visible for this map state.</p>
    }
    else
    {
        <div class="relationship-map-list">
            @foreach (var relationship in Model.Relationships)
            {
                <button class="relationship-map-list-item" type="button" data-map-select="@relationship.CharacterRelationshipID">
                    <strong>@relationship.CharacterAName - @relationship.CharacterBName</strong>
                    <span>@relationship.CurrentStateName</span>
                    <span class="status-pill @relationship.CssClass">@relationship.RelationshipCategoryName</span>
                </button>
            }
        </div>
    }
</section>

@section Scripts {
    <script src="https://cdn.jsdelivr.net/npm/cytoscape/dist/cytoscape.min.js"></script>
    <script>
        (() => {
            const nodes = @Html.Raw(JsonSerializer.Serialize(Model.Nodes, jsonOptions));
            const links = @Html.Raw(JsonSerializer.Serialize(Model.Links, jsonOptions));
            const relationships = @Html.Raw(JsonSerializer.Serialize(Model.Relationships, jsonOptions));
            const relationshipById = new Map(relationships.map(item => [item.characterRelationshipID, item]));
            const graph = document.getElementById("relationshipMapGraph");
            const error = document.getElementById("relationshipMapError");
            if (!graph || !nodes.length) return;

            if (!window.cytoscape) {
                error?.classList.remove("d-none");
                return;
            }

            const focusCharacterId = @Html.Raw(JsonSerializer.Serialize(Model.FocusCharacterID));
            const fullNetwork = @Html.Raw(JsonSerializer.Serialize(Model.ShowFullNetwork));
            const connectedToFocus = new Set();
            if (focusCharacterId && fullNetwork) {
                links.forEach(link => {
                    if (link.sourceCharacterID === focusCharacterId) connectedToFocus.add(link.targetCharacterID);
                    if (link.targetCharacterID === focusCharacterId) connectedToFocus.add(link.sourceCharacterID);
                });
            }

            const elements = [
                ...nodes.map(node => ({
                    group: "nodes",
                    data: {
                        id: `c-${node.characterID}`,
                        characterID: node.characterID,
                        label: node.characterName,
                        importance: node.characterImportance || 0,
                        width: node.isFocus ? 172 : node.characterImportance >= 8 ? 158 : node.characterImportance >= 4 ? 144 : 128,
                        height: node.isFocus ? 58 : node.characterImportance >= 8 ? 52 : 46,
                        isFocus: node.isFocus,
                        isNeighbour: connectedToFocus.has(node.characterID)
                    },
                    classes: [
                        node.isFocus ? "is-focus" : "",
                        node.characterImportance >= 8 ? "is-major-character" : "",
                        node.characterImportance >= 4 && node.characterImportance < 8 ? "is-supporting-character" : "",
                        focusCharacterId && fullNetwork && !node.isFocus && !connectedToFocus.has(node.characterID) ? "is-dimmed" : ""
                    ].filter(Boolean).join(" ")
                })),
                ...links.map(link => ({
                    group: "edges",
                    data: {
                        id: `r-${link.characterRelationshipID}`,
                        relationshipID: link.characterRelationshipID,
                        source: `c-${link.sourceCharacterID}`,
                        target: `c-${link.targetCharacterID}`,
                        label: link.relationshipLabel,
                        category: link.categoryName,
                        intensity: link.intensity || 4,
                        tooltip: buildRelationshipTooltip(relationshipById.get(link.characterRelationshipID))
                    },
                    classes: [
                        link.cssClass,
                        focusCharacterId && fullNetwork && link.sourceCharacterID !== focusCharacterId && link.targetCharacterID !== focusCharacterId ? "is-dimmed" : ""
                    ].filter(Boolean).join(" ")
                }))
            ];

            const cy = cytoscape({
                container: graph,
                elements,
                minZoom: 0.25,
                maxZoom: 2.5,
                wheelSensitivity: 0.18,
                style: relationshipMapStyle(),
                layout: {
                    name: nodes.length <= 8 ? "circle" : "cose",
                    animate: false,
                    fit: true,
                    padding: 48,
                    nodeRepulsion: 9000,
                    idealEdgeLength: 170,
                    edgeElasticity: 80,
                    numIter: 1200,
                    randomize: false
                }
            });

            cy.ready(() => {
                cy.fit(undefined, 48);
                const first = relationships[0];
                if (first) selectRelationship(first.characterRelationshipID);
            });

            cy.on("tap", "edge", event => {
                selectRelationship(event.target.data("relationshipID"));
            });

            cy.on("tap", "node", event => {
                const characterId = event.target.data("characterID");
                const characterName = event.target.data("label");
                document.getElementById("relationshipMapEmptyDetail")?.classList.add("d-none");
                document.getElementById("relationshipMapDetail")?.classList.remove("d-none");
                document.querySelector("[data-map-detail-title]").textContent = characterName;
                document.querySelector("[data-map-detail-category]").textContent = "Character";
                document.querySelector("[data-map-detail-reciprocal]").textContent = characterId === focusCharacterId ? "Focused" : "Node";
                document.querySelector("[data-map-detail-type]").textContent = "Character";
                document.querySelector("[data-map-detail-initial]").textContent = "Select a relationship line to see relationship state.";
                document.querySelector("[data-map-detail-current]").textContent = "Use Character focus to centre this character.";
                const history = document.querySelector("[data-map-detail-history]");
                history.innerHTML = "";
                const li = document.createElement("li");
                li.innerHTML = `<a href="/Characters/Details/${characterId}">Open character details</a> or <a href="/RelationshipMap?projectId=@Model.Project.ProjectID&focusCharacterId=${characterId}">focus this character</a>.`;
                history.append(li);
            });

            cy.on("mouseover", "node, edge", event => {
                const label = event.target.isNode() ? event.target.data("label") : event.target.data("tooltip");
                graph.setAttribute("title", label || "");
            });

            document.querySelector("[data-map-fit]")?.addEventListener("click", () => {
                cy.resize();
                cy.fit(undefined, 48);
            });

            document.querySelector("[data-map-reset]")?.addEventListener("click", () => {
                cy.layout({
                    name: nodes.length <= 8 ? "circle" : "cose",
                    animate: false,
                    fit: true,
                    padding: 48,
                    randomize: false
                }).run();
            });

            window.addEventListener("resize", () => {
                window.requestAnimationFrame(() => {
                    cy.resize();
                    cy.fit(undefined, 48);
                });
            });

            document.querySelectorAll("[data-map-select]").forEach(button => {
                button.addEventListener("click", () => selectRelationship(Number(button.dataset.mapSelect)));
            });

            function selectRelationship(id) {
                const relationship = relationshipById.get(id);
                if (!relationship) return;

                cy.elements().removeClass("is-selected");
                cy.$id(`r-${id}`).addClass("is-selected");
                document.querySelectorAll(".relationship-map-list-item").forEach(item => item.classList.remove("is-selected"));
                document.querySelectorAll(`[data-map-select="${id}"]`).forEach(item => item.classList.add("is-selected"));

                document.getElementById("relationshipMapEmptyDetail")?.classList.add("d-none");
                document.getElementById("relationshipMapDetail")?.classList.remove("d-none");
                document.querySelector("[data-map-detail-title]").textContent = `${relationship.characterAName} - ${relationship.characterBName}`;
                document.querySelector("[data-map-detail-category]").textContent = relationship.relationshipCategoryName;
                document.querySelector("[data-map-detail-reciprocal]").textContent = relationship.isReciprocal ? "Reciprocal" : "Directional";
                document.querySelector("[data-map-detail-type]").textContent = relationship.relationshipTypeName;
                document.querySelector("[data-map-detail-initial]").textContent = formatState(relationship.initialStateName, relationship.initialIntensity);
                document.querySelector("[data-map-detail-current]").textContent = formatState(relationship.currentStateName, relationship.currentIntensity);

                const history = document.querySelector("[data-map-detail-history]");
                history.innerHTML = "";
                relationship.history.forEach(item => {
                    const li = document.createElement("li");
                    const notes = item.notes ? ` - ${item.notes}` : "";
                    li.textContent = `${item.label}: ${formatState(item.stateName, item.intensity)}${notes}`;
                    history.append(li);
                });
            }

            function formatState(name, intensity) {
                return intensity ? `${name} / Intensity ${intensity}` : name;
            }

            function buildRelationshipTooltip(relationship) {
                if (!relationship) return "";
                return `${relationship.characterAName} - ${relationship.characterBName}: ${relationship.relationshipTypeName}; current ${formatState(relationship.currentStateName, relationship.currentIntensity)}`;
            }

            function relationshipMapStyle() {
                const isDark = document.documentElement.dataset.theme === "dark";
                const nodeFill = isDark ? "#222126" : "#fffdf8";
                const nodeText = isDark ? "#f7efe4" : "#1f2937";
                const focusFill = isDark ? "#3b2a16" : "#fff3d8";
                const majorFill = isDark ? "#332417" : "#fff0d5";
                const supportingFill = isDark ? "#29252c" : "#fbf6ef";
                const labelFill = isDark ? "#f7efe4" : "#2f3742";
                const labelBackground = isDark ? "#17171c" : "#fffdf8";
                return [
                    {
                        selector: "node",
                        style: {
                            "label": "data(label)",
                            "shape": "round-rectangle",
                            "width": "data(width)",
                            "height": "data(height)",
                            "background-color": nodeFill,
                            "border-color": "#6b7280",
                            "border-width": 2,
                            "color": nodeText,
                            "font-size": 12,
                            "font-weight": 650,
                            "text-wrap": "wrap",
                            "text-max-width": 118,
                            "text-valign": "center",
                            "text-halign": "center",
                            "text-margin-y": 0,
                            "padding": "10px",
                            "shadow-blur": 10,
                            "shadow-color": isDark ? "rgba(0, 0, 0, 0.45)" : "rgba(31, 41, 55, 0.18)",
                            "shadow-opacity": 0.32,
                            "shadow-offset-y": 3,
                            "overlay-opacity": 0
                        }
                    },
                    {
                        selector: "node.is-supporting-character",
                        style: {
                            "background-color": supportingFill,
                            "border-color": isDark ? "#b9a891" : "#b99970",
                            "border-width": 2.5,
                            "font-weight": 700
                        }
                    },
                    {
                        selector: "node.is-major-character",
                        style: {
                            "background-color": majorFill,
                            "border-color": "#c47c2c",
                            "border-width": 3,
                            "font-size": 13,
                            "font-weight": 800,
                            "shadow-opacity": 0.42
                        }
                    },
                    {
                        selector: "node.is-focus",
                        style: {
                            "width": "data(width)",
                            "height": "data(height)",
                            "background-color": focusFill,
                            "border-color": "#c47c2c",
                            "border-width": 4,
                            "font-size": 13,
                            "font-weight": 850,
                            "shadow-opacity": 0.5
                        }
                    },
                    {
                        selector: "edge",
                        style: {
                            "label": "data(label)",
                            "curve-style": "bezier",
                            "width": "mapData(intensity, 1, 10, 2, 8)",
                            "line-color": "#7a8796",
                            "target-arrow-shape": "none",
                            "font-size": 11,
                            "font-weight": 700,
                            "color": labelFill,
                            "text-background-color": labelBackground,
                            "text-background-opacity": 0.88,
                            "text-background-padding": 3,
                            "text-rotation": "none",
                            "overlay-opacity": 0
                        }
                    },
                    { selector: "edge.relationship-category-family", style: { "line-color": "#b86522", "color": "#7c3f12" } },
                    { selector: "edge.relationship-category-friendship", style: { "line-color": "#2f9e5f", "color": "#14532d" } },
                    { selector: "edge.relationship-category-romantic", style: { "line-color": "#d9467f", "color": "#831843" } },
                    { selector: "edge.relationship-category-hostile", style: { "line-color": "#dc3f3f", "color": "#7f1d1d" } },
                    { selector: "edge.relationship-category-professional", style: { "line-color": "#4f7fd8", "color": "#1e3a8a" } },
                    { selector: "edge.relationship-category-other", style: { "line-color": "#7a8796", "color": "#374151" } },
                    {
                        selector: ".is-dimmed",
                        style: {
                            "opacity": 0.25
                        }
                    },
                    {
                        selector: "edge.is-selected",
                        style: {
                            "width": 9,
                            "z-index": 20,
                            "text-background-opacity": 1
                        }
                    },
                    {
                        selector: "node:selected",
                        style: {
                            "border-color": "#c47c2c",
                            "border-width": 4
                        }
                    }
                ];
            }
        })();
    </script>
}
