function escape(value) {
    return foundry.utils.escapeHTML(String(value || ""));
}

function listSection(label, rows = [], { className = "" } = {}) {
    if (!rows.length) return "";
    const items = rows.map(row => `
        <li class="nexus-delete-structural-row">
            <i class="fa-solid fa-trash-can" aria-hidden="true"></i>
            <span>${escape(row.name || row.label || "Unknown")}</span>
            <span class="nexus-delete-row-status">Will Delete</span>
        </li>
    `).join("");
    return `
        <details class="nexus-delete-impact-section nexus-delete-structural ${className}" open>
            <summary>${escape(label)} (${rows.length})</summary>
            <ul>${items}</ul>
        </details>
    `;
}

function candidateSection(label, rows = []) {
    if (!rows.length) return "";
    const items = rows.map(row => `
        <li class="nexus-delete-candidate-row is-delete" data-deletion-entity-row="${escape(row.id)}">
            <label>
                <input
                    type="checkbox"
                    checked
                    data-deletion-entity-id="${escape(row.id)}"
                    data-deletion-component-id="${escape(row.componentId)}"
                >
                <span class="nexus-delete-candidate-name">${escape(row.name || "Unknown")}</span>
                <span class="nexus-delete-row-status" data-deletion-status>Delete</span>
            </label>
        </li>
    `).join("");
    return `
        <details class="nexus-delete-impact-section nexus-delete-candidates" open>
            <summary>${escape(label)} (${rows.length})</summary>
            <ul>${items}</ul>
        </details>
    `;
}

function groupedCandidates(rows = []) {
    const groups = [
        { type: "npc", label: "People" },
        { type: "ship", label: "Ships" },
        { type: "faction", label: "Organizations" }
    ];
    return groups.map(group =>
        candidateSection(group.label, rows.filter(row => row.entityType === group.type))
    ).join("");
}

export class NexusDeletionConfirmation {
    static getDefaultSelection(plan = {}) {
        return (plan.entityCandidates || []).map(row => row.id);
    }

    static readCandidateSelection(root, plan = {}) {
        if (!root?.querySelectorAll) return this.getDefaultSelection(plan);
        return [...root.querySelectorAll("[data-deletion-entity-id]:checked")]
            .map(input => input.dataset.deletionEntityId || "")
            .filter(Boolean);
    }

    static attachCandidateSelection(root, plan = {}) {
        if (!root?.querySelectorAll) return;
        const rows = plan.entityCandidates || [];
        if (!rows.length) return;

        const candidatesById = new Map(rows.map(row => [row.id, row]));
        const componentMembers = new Map();
        for (const row of rows) {
            const componentId = row.componentId || row.id;
            const members = componentMembers.get(componentId) || [];
            members.push(row.id);
            componentMembers.set(componentId, members);
        }

        const inputs = [...root.querySelectorAll("[data-deletion-entity-id]")];
        const inputById = new Map(inputs.map(input => [input.dataset.deletionEntityId, input]));
        const selectAll = root.querySelector("[data-deletion-select-all]");
        const notice = root.querySelector("[data-deletion-selection-notice]");

        const updateRow = input => {
            const row = input.closest("[data-deletion-entity-row]");
            const status = row?.querySelector("[data-deletion-status]");
            row?.classList.toggle("is-delete", input.checked);
            row?.classList.toggle("is-keep", !input.checked);
            if (status) status.textContent = input.checked ? "Delete" : "Keep";
        };

        const updateSelectAll = () => {
            if (!selectAll) return;
            const checkedCount = inputs.filter(input => input.checked).length;
            selectAll.checked = checkedCount === inputs.length;
            selectAll.indeterminate = checkedCount > 0 && checkedCount < inputs.length;
        };

        const setComponent = (componentId, checked, changedEntityId) => {
            const members = componentMembers.get(componentId) || [changedEntityId];
            for (const entityId of members) {
                const input = inputById.get(entityId);
                if (!input) continue;
                input.checked = checked;
                updateRow(input);
            }
            updateSelectAll();

            if (!notice) return;
            const changed = candidatesById.get(changedEntityId);
            const relatedCount = Math.max(0, members.length - 1);
            notice.textContent = checked
                ? relatedCount
                    ? `Deleting ${changed?.name || "this entity"} also selected ${relatedCount} connected ${relatedCount === 1 ? "entity" : "entities"}.`
                    : `${changed?.name || "This entity"} will be deleted.`
                : relatedCount
                    ? `Preserving ${changed?.name || "this entity"} also preserved ${relatedCount} connected ${relatedCount === 1 ? "entity" : "entities"}.`
                    : `${changed?.name || "This entity"} will be preserved.`;
        };

        for (const input of inputs) {
            updateRow(input);
            input.addEventListener("change", () => {
                setComponent(
                    input.dataset.deletionComponentId || input.dataset.deletionEntityId,
                    input.checked,
                    input.dataset.deletionEntityId
                );
            });
        }

        selectAll?.addEventListener("change", () => {
            for (const input of inputs) {
                input.checked = selectAll.checked;
                updateRow(input);
            }
            updateSelectAll();
            if (notice) {
                notice.textContent = selectAll.checked
                    ? "All branch-local entities are selected for deletion."
                    : "All branch-local entities will be preserved.";
            }
        });
        updateSelectAll();
    }

    static renderImpact(plan = {}, {
        baseImpact = null,
        participantImpacts = null,
        includeScenes = true
    } = {}) {
        const impacts = participantImpacts || plan.participantImpacts || [];
        const candidates = plan.entityCandidates || [];
        const auxiliaryRows = [
            { label: "site pin", count: Number(baseImpact?.noteCount || 0) },
            { label: "journal page", count: Number(baseImpact?.pageCount || 0) },
            { label: "site journal entry", count: Number(baseImpact?.journalEntryCount || 0) },
            ...impacts
        ].filter(row => Number(row.count || 0) > 0);
        const auxiliary = auxiliaryRows.length
            ? `<ul class="nexus-delete-impact-counts">${auxiliaryRows.map(row => {
                const count = Number(row.count || 0);
                return `<li>${count} ${escape(row.label)}${count === 1 ? "" : "s"}</li>`;
            }).join("")}</ul>`
            : "";
        const selectionControls = candidates.length
            ? `
                <div class="nexus-delete-selection-controls">
                    <label>
                        <input type="checkbox" checked data-deletion-select-all>
                        <span>Delete all branch-local entities</span>
                    </label>
                    <p>Unticking one entity preserves its connected candidate group.</p>
                    <p class="nexus-delete-selection-notice" data-deletion-selection-notice aria-live="polite"></p>
                </div>
            `
            : "";
        const preserved = (plan.preservedEntities || []).length
            ? `
                <details class="nexus-delete-impact-section nexus-delete-preserved">
                    <summary>Protected linked entities (${plan.preservedEntities.length})</summary>
                    <ul>${plan.preservedEntities.map(row =>
                        `<li><strong>${escape(row.name)}</strong> &mdash; ${escape((row.reasons || []).join("; ") || "ambiguous relationship")}</li>`
                    ).join("")}</ul>
                </details>
            `
            : "";

        return `
            <div class="nexus-delete-impact-list">
                ${includeScenes ? listSection("Scenes", plan.scenes || []) : ""}
                ${listSection("Locations", plan.locations || [])}
                ${listSection("Shops", plan.shops || [])}
                <p class="nexus-delete-structural-note">Child Scenes and Locations are always deleted with their parent.</p>
                ${selectionControls}
                ${groupedCandidates(candidates)}
                ${auxiliary}
                ${preserved}
            </div>
        `;
    }

    static async confirm(plan = {}, {
        title = "Confirm Delete",
        message = "Delete the selected content and everything explicitly contained beneath it?",
        warning = "This cannot be undone.",
        confirmLabel = "Delete",
        baseImpact = null,
        participantImpacts = null,
        includeScenes = true
    } = {}) {
        let dialogRoot = null;
        const result = await foundry.applications.api.DialogV2.wait({
            classes: ["dialog", "augur-nexus", "nexus-cascade-delete-dialog"],
            window: {
                title,
                icon: "fa-solid fa-triangle-exclamation"
            },
            position: { width: 560 },
            modal: true,
            rejectClose: false,
            content: `
                <div class="nexus-delete-confirm">
                    <p>${message}</p>
                    ${this.renderImpact(plan, { baseImpact, participantImpacts, includeScenes })}
                    <p>This cannot be undone.</p>
                    ${warning ? `<p class="nexus-delete-confirm-warning">${escape(warning)}</p>` : ""}
                </div>
            `,
            buttons: [
                {
                    action: "confirm",
                    label: confirmLabel,
                    icon: "fa-solid fa-trash",
                    class: "nexus-delete-confirm-submit",
                    callback: () => ({
                        selectedEntityIds: this.readCandidateSelection(dialogRoot, plan)
                    })
                },
                {
                    action: "cancel",
                    label: "Cancel",
                    icon: "fa-solid fa-xmark",
                    class: "nexus-delete-confirm-cancel",
                    default: true,
                    callback: () => false
                }
            ],
            render: (_event, dialog) => {
                dialogRoot = dialog.element;
                this.attachCandidateSelection(dialogRoot, plan);
            }
        });
        return result && result !== false ? result : false;
    }
}
