// plan-review.js — the doc-controller "Plan Review" workflow modal.
//
// Surfaced by events.js as a right-click menu item on
// archive/<party>/received/<tracking>/ folders when the cascade above
// has an on_plan_review block (X-ZDDC-On-Plan-Review header on the
// listing).
//
// The modal collects four fields:
//
//   - review_lead                (becomes sub-admin of reviewing/<…>/)
//   - plan_review_complete_date  (the committed review-done date)
//   - approver                   (becomes sub-admin of staging/<…>/)
//   - plan_response_date         (the committed response-issue date)
//
// The planned dates are immutable from the sub-admins' perspective —
// they live in the canonical submittal's .zddc
// (received/<tracking>/.zddc) where only the doc controller (via Plan
// Review re-run) can change them. The workflow folders' .zddc files
// carry only the back-link + per-folder ACL.
//
// Title is auto-derived server-side from the first ZDDC-parseable
// file in received/<tracking>/. Forecast dates default to the planned
// dates at scaffolding time; the user renames the workflow folder
// directly to update the forecast later.
//
// On submit, the form assembles a YAML body and POSTs it with
// X-ZDDC-Op: plan-review to the received/<tracking>/ URL.

(function () {
    'use strict';

    var REVIEW_OFFSET_DAYS = 7;
    var RESPONSE_OFFSET_DAYS = 14;

    function statusInfo(msg) {
        var el = document.getElementById('statusBar');
        if (!el) return;
        el.textContent = msg || '';
        el.classList.remove('status-bar--error');
        el.classList.add('status-bar--info');
    }
    function statusError(msg) {
        var el = document.getElementById('statusBar');
        if (!el) return;
        el.textContent = msg || '';
        el.classList.remove('status-bar--info');
        el.classList.add('status-bar--error');
    }

    // Compute today + N days as a YYYY-MM-DD string.
    function isoDatePlus(days) {
        var d = new Date();
        d.setDate(d.getDate() + days);
        var y = d.getFullYear();
        var m = ('0' + (d.getMonth() + 1)).slice(-2);
        var dd = ('0' + d.getDate()).slice(-2);
        return y + '-' + m + '-' + dd;
    }

    // Fetch suggestion emails from /.profile/access so the originator
    // field has a datalist of likely values. Best-effort — silent on
    // failure (the field still accepts free text).
    async function fetchOriginatorSuggestions() {
        try {
            var resp = await fetch('/.profile/access', {
                headers: { 'Accept': 'application/json' },
                credentials: 'same-origin'
            });
            if (!resp.ok) return [];
            var data = await resp.json();
            var out = [];
            // The endpoint exposes the current user + any role members
            // visible to them. Pull anything that looks like an email
            // for the datalist; the field is otherwise free text.
            if (data && data.email) out.push(data.email);
            return out;
        } catch (_e) {
            return [];
        }
    }

    // Build the YAML body for the plan-review POST. Quoting is minimal
    // (just enough for emails with special chars).
    function buildBody(values) {
        function yamlString(s) {
            return '"' + String(s).replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
        }
        return [
            'review_lead: ' + yamlString(values.reviewLead),
            'approver: ' + yamlString(values.approver),
            'plan_review_complete_date: ' + values.planReviewDate,
            'plan_response_date: ' + values.planResponseDate,
            ''
        ].join('\n');
    }

    // Render the modal. Returns a Promise that resolves on submit
    // (with the collected values) or rejects on cancel.
    function openForm(initial) {
        return new Promise(function (resolve, reject) {
            var overlay = document.createElement('div');
            overlay.className = 'modal-overlay';
            overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.4);display:flex;align-items:center;justify-content:center;z-index:9000;';

            var box = document.createElement('div');
            box.style.cssText = 'background:var(--bg,#fff);color:var(--fg,#111);padding:1.25rem 1.5rem;border-radius:6px;min-width:24rem;max-width:32rem;box-shadow:0 4px 20px rgba(0,0,0,0.25);font-family:inherit;';

            box.innerHTML =
                '<h2 style="margin:0 0 0.75rem 0;font-size:1.1rem;">Plan Review — ' + escapeHtml(initial.tracking) + '</h2>' +
                '<div style="display:grid;grid-template-columns:max-content 1fr;gap:0.5rem 0.75rem;align-items:center;font-size:0.9rem;">' +
                  '<label for="pr-review-lead">Review lead</label>' +
                  '<input id="pr-review-lead" type="email" list="pr-people-list" required style="padding:0.25rem 0.4rem;" placeholder="email — becomes sub-admin of reviewing/<…>">' +
                  '<label for="pr-review-date">Plan review complete date</label>' +
                  '<input id="pr-review-date" type="date" required>' +
                  '<label for="pr-approver">Approver</label>' +
                  '<input id="pr-approver" type="email" list="pr-people-list" required style="padding:0.25rem 0.4rem;" placeholder="email — becomes sub-admin of staging/<…>">' +
                  '<label for="pr-response-date">Plan response date</label>' +
                  '<input id="pr-response-date" type="date" required>' +
                  '<datalist id="pr-people-list"></datalist>' +
                '</div>' +
                '<p style="margin:0.75rem 0 0 0;font-size:0.8rem;color:#666;">Planned dates seal at first submission — they become part of the canonical record (received/<tracking>/.zddc) and the WORM zone prevents further edits. Subsequent Plan Reviews can swap the review lead or approver without changing the dates.</p>' +
                '<div style="display:flex;justify-content:flex-end;gap:0.5rem;margin-top:1rem;">' +
                  '<button type="button" id="pr-cancel">Cancel</button>' +
                  '<button type="button" id="pr-submit" class="btn-primary">Plan Review</button>' +
                '</div>';

            overlay.appendChild(box);
            document.body.appendChild(overlay);

            var reviewLeadInput = box.querySelector('#pr-review-lead');
            var approverInput = box.querySelector('#pr-approver');
            var reviewDateInput = box.querySelector('#pr-review-date');
            var responseDateInput = box.querySelector('#pr-response-date');

            reviewDateInput.value = isoDatePlus(REVIEW_OFFSET_DAYS);
            responseDateInput.value = isoDatePlus(RESPONSE_OFFSET_DAYS);

            // Populate the datalist with people suggestions (best
            // effort — silent on failure).
            fetchOriginatorSuggestions().then(function (emails) {
                var dl = box.querySelector('#pr-people-list');
                if (!dl) return;
                emails.forEach(function (e) {
                    var opt = document.createElement('option');
                    opt.value = e;
                    dl.appendChild(opt);
                });
            });

            function close() {
                if (overlay.parentNode) overlay.parentNode.removeChild(overlay);
            }

            box.querySelector('#pr-cancel').addEventListener('click', function () {
                close();
                reject(new Error('cancelled'));
            });
            overlay.addEventListener('click', function (e) {
                if (e.target === overlay) {
                    close();
                    reject(new Error('cancelled'));
                }
            });
            document.addEventListener('keydown', function escHandler(e) {
                if (e.key === 'Escape') {
                    document.removeEventListener('keydown', escHandler);
                    close();
                    reject(new Error('cancelled'));
                }
            });

            box.querySelector('#pr-submit').addEventListener('click', function () {
                var values = {
                    reviewLead: reviewLeadInput.value.trim(),
                    approver: approverInput.value.trim(),
                    planReviewDate: reviewDateInput.value,
                    planResponseDate: responseDateInput.value
                };
                if (!values.reviewLead || !values.approver
                    || !values.planReviewDate || !values.planResponseDate) {
                    statusError('All fields are required.');
                    return;
                }
                close();
                resolve(values);
            });

            reviewLeadInput.focus();
        });
    }

    function escapeHtml(s) {
        return String(s).replace(/[&<>"']/g, function (c) {
            return ({
                '&': '&amp;', '<': '&lt;', '>': '&gt;',
                '"': '&quot;', "'": '&#39;'
            })[c];
        });
    }

    // Detect whether a tree node is an archive/<party>/received/<tracking>/
    // folder. The path is path-shaped, not content-based — tracking-number
    // content is not inspected (per design).
    function isReceivedTrackingFolder(node) {
        if (!node || !node.isDir) return false;
        var tree = window.app.modules.tree;
        if (!tree) return false;
        var p = tree.pathFor(node).replace(/\/$/, '');
        var rel = p.replace(/^\/+/, '');
        var parts = rel.split('/');
        return parts.length === 5
            && parts[1].toLowerCase() === 'archive'
            && parts[3].toLowerCase() === 'received';
    }

    // Run the Plan Review flow: open the modal, POST the result.
    async function invoke(node) {
        var tree = window.app.modules.tree;
        if (!tree) return;
        var url = tree.pathFor(node);
        if (!url.endsWith('/')) url += '/';
        var parts = url.replace(/^\/+/, '').replace(/\/$/, '').split('/');
        var tracking = parts[parts.length - 1];

        var values;
        try {
            values = await openForm({ tracking: tracking });
        } catch (_e) {
            return; // cancelled
        }

        statusInfo('Plan Review — submitting…');
        var body = buildBody(values);
        var resp;
        try {
            resp = await fetch(url, {
                method: 'POST',
                headers: {
                    'X-ZDDC-Op': 'plan-review',
                    'Content-Type': 'application/yaml'
                },
                body: body,
                credentials: 'same-origin'
            });
        } catch (e) {
            statusError('Plan Review failed: ' + (e && e.message ? e.message : e));
            return;
        }
        if (!resp.ok) {
            var text = '';
            try { text = await resp.text(); } catch (_e) { /* ignore */ }
            statusError('Plan Review failed (' + resp.status + '): ' + text);
            return;
        }
        var data;
        try { data = await resp.json(); } catch (_e) { data = null; }
        if (data && data.reviewing && data.staging) {
            var rPart = data.reviewing.created ? 'created' : 'updated';
            var sPart = data.staging.created ? 'created' : 'updated';
            var seal = (data.received && data.received.created)
                ? ' Canonical record sealed.'
                : (data.received && !data.received.zddc_written)
                    ? ' Canonical dates left untouched (already sealed).'
                    : '';
            statusInfo('Plan Review: reviewing ' + rPart + ', staging ' + sPart + '.' + seal +
                ' Reload the relevant folder to see the new entries.');
        } else {
            statusInfo('Plan Review complete.');
        }
    }

    window.app.modules.planReview = {
        isReceivedTrackingFolder: isReceivedTrackingFolder,
        invoke: invoke
    };
})();
