// manage-access.js — guided "who can do what here" dialog. A task-first
// front door for a folder's .zddc acl: the user picks people + friendly access
// levels; we read the on-disk .zddc, merge ONLY the access bits (preserving
// every other key), and PUT it. No YAML, no schema knowledge required. The raw
// editor stays as the "Advanced" escape hatch.
//
// Friendly level → verbs (r read, w overwrite, c create, d delete, a admin):
//   View       → r        Contribute → rc
//   Edit       → rwc      Manage     → admins: membership (not a verb string)
// "Custom" preserves a hand-written verb string we don't recognise.
(function (app) {
    'use strict';
    if (!app || !app.modules) return;
    var util = app.modules.util;

    var LEVELS = [
        { id: 'view', label: 'View', hint: 'read only', verbs: 'r' },
        { id: 'contribute', label: 'Contribute', hint: 'read + add new files', verbs: 'rc' },
        { id: 'edit', label: 'Edit', hint: 'read, overwrite, add', verbs: 'rwc' },
        { id: 'manage', label: 'Manage', hint: 'full config + (elevated) bypass', verbs: null }
    ];
    function verbsOfLevel(id) {
        for (var i = 0; i < LEVELS.length; i++) if (LEVELS[i].id === id) return LEVELS[i].verbs;
        return null;
    }
    function levelOfVerbs(verbs) {
        verbs = String(verbs || '');
        if (verbs.indexOf('a') !== -1) return 'manage';
        if (verbs.indexOf('w') !== -1) return 'edit';
        if (verbs.indexOf('c') !== -1) return 'contribute';
        if (verbs.indexOf('r') !== -1) return 'view';
        return 'custom'; // empty (explicit deny) or non-standard
    }

    function dirUrl(dir) {
        var u = dir || '/';
        if (u.charAt(0) !== '/') u = '/' + u;
        if (u.charAt(u.length - 1) !== '/') u += '/';
        return u;
    }

    function el(tag, cls, text) {
        var e = document.createElement(tag);
        if (cls) e.className = cls;
        if (text != null) e.textContent = text;
        return e;
    }

    async function open(dir) {
        if (!app.state || app.state.source !== 'server') {
            toast('Access management needs the server.', 'error');
            return;
        }
        var base = dirUrl(dir);
        var zddcUrl = base + '.zddc';
        var data = {}, etag = null;
        try {
            var r = await fetch(zddcUrl, { credentials: 'same-origin' });
            if (r.ok) {
                etag = r.headers.get('ETag');
                var txt = await r.text();
                try { data = (window.jsyaml && window.jsyaml.load(txt)) || {}; } catch (_e) { data = {}; }
            } else if (r.status !== 404) {
                throw new Error('HTTP ' + r.status);
            }
        } catch (e) {
            toast('Could not read access rules: ' + (e.message || e), 'error');
            return;
        }
        if (!data || typeof data !== 'object' || Array.isArray(data)) data = {};

        // Build the principal → level model from admins (Manage) + acl.permissions.
        var acl = (data.acl && typeof data.acl === 'object') ? data.acl : {};
        var perms = (acl.permissions && typeof acl.permissions === 'object') ? acl.permissions : {};
        var admins = Array.isArray(data.admins) ? data.admins : [];
        var rows = [];
        var seen = {};
        admins.forEach(function (p) {
            if (typeof p === 'string' && !seen[p]) { seen[p] = 1; rows.push({ principal: p, level: 'manage', custom: '' }); }
        });
        Object.keys(perms).forEach(function (p) {
            if (seen[p]) return;
            seen[p] = 1;
            var lvl = levelOfVerbs(perms[p]);
            rows.push({ principal: p, level: lvl, custom: lvl === 'custom' ? String(perms[p] || '') : '' });
        });
        var inherit = acl.inherit !== false;

        renderModal(base, zddcUrl, data, etag, rows, inherit);
    }

    function toast(msg, kind) { if (window.zddc && window.zddc.toast) window.zddc.toast(msg, kind || 'info'); }

    function renderModal(base, zddcUrl, data, etag, rows, inherit) {
        var overlay = el('div', 'ma-overlay');
        var box = el('div', 'ma-box');
        overlay.appendChild(box);

        box.appendChild(el('h2', 'ma-title', 'Manage access'));
        var sub = el('p', 'ma-sub', 'Who can do what in ' + base + ' — changes here only.');
        box.appendChild(sub);

        var list = el('div', 'ma-list');
        box.appendChild(list);

        function addRow(model) {
            var row = el('div', 'ma-row');
            var who = el('input', 'ma-who');
            who.type = 'text';
            who.value = model.principal || '';
            who.placeholder = 'email or *@domain or role name';
            who.addEventListener('input', function () { model.principal = who.value.trim(); });

            var sel = el('select', 'ma-level');
            LEVELS.forEach(function (lv) {
                var o = el('option', null, lv.label);
                o.value = lv.id;
                o.title = lv.hint;
                sel.appendChild(o);
            });
            if (model.level === 'custom') {
                var o2 = el('option', null, 'Custom');
                o2.value = 'custom';
                o2.title = 'verbs: ' + model.custom;
                sel.appendChild(o2);
            }
            sel.value = model.level;
            sel.addEventListener('change', function () { model.level = sel.value; });

            var del = el('button', 'ma-del', '✕');
            del.type = 'button';
            del.title = 'Remove';
            del.addEventListener('click', function () { row.remove(); model._removed = true; });

            row.appendChild(who);
            row.appendChild(sel);
            row.appendChild(del);
            list.appendChild(row);
            return model;
        }
        rows.forEach(addRow);

        var addBtn = el('button', 'ma-add', '+ Add person or group');
        addBtn.type = 'button';
        addBtn.addEventListener('click', function () {
            var m = { principal: '', level: 'view', custom: '' };
            rows.push(m);
            addRow(m);
        });
        box.appendChild(addBtn);

        var legend = el('p', 'ma-legend',
            'View = read · Contribute = add new files · Edit = overwrite + add · Manage = admin');
        box.appendChild(legend);

        // Inherit / make-private.
        var inhWrap = el('label', 'ma-inherit');
        var inhBox = el('input');
        inhBox.type = 'checkbox';
        inhBox.checked = inherit;
        inhWrap.appendChild(inhBox);
        inhWrap.appendChild(el('span', null, ' Inherit access from parent folders'));
        box.appendChild(inhWrap);

        var err = el('p', 'ma-err');
        box.appendChild(err);

        var actions = el('div', 'ma-actions');
        var cancel = el('button', 'btn btn-sm btn-secondary', 'Cancel');
        cancel.type = 'button';
        var save = el('button', 'btn btn-sm btn-primary', 'Save');
        save.type = 'button';
        actions.appendChild(cancel);
        actions.appendChild(save);
        box.appendChild(actions);

        function close() {
            document.removeEventListener('keydown', onKey, true);
            if (overlay.parentNode) overlay.parentNode.removeChild(overlay);
        }
        function onKey(e) { if (e.key === 'Escape') { e.preventDefault(); close(); } }
        document.addEventListener('keydown', onKey, true);
        overlay.addEventListener('mousedown', function (e) { if (e.target === overlay) close(); });
        cancel.addEventListener('click', close);

        save.addEventListener('click', function () {
            err.textContent = '';
            // Rebuild perms + admins from the live rows (skip removed/blank).
            var perms = {}, admins = [], bad = false;
            rows.forEach(function (m) {
                if (m._removed) return;
                var p = (m.principal || '').trim();
                if (!p) return;
                if (m.level === 'manage') {
                    if (admins.indexOf(p) === -1) admins.push(p);
                } else if (m.level === 'custom') {
                    perms[p] = m.custom; // preserve the hand-written string
                } else {
                    perms[p] = verbsOfLevel(m.level);
                }
            });

            // Merge into the existing doc, preserving every unmanaged key.
            var out = {};
            Object.keys(data).forEach(function (k) { out[k] = data[k]; });
            var acl = (out.acl && typeof out.acl === 'object') ? Object.assign({}, out.acl) : {};
            if (Object.keys(perms).length) acl.permissions = perms; else delete acl.permissions;
            if (!inhBox.checked) acl.inherit = false; else delete acl.inherit;
            if (Object.keys(acl).length) out.acl = acl; else delete out.acl;
            if (admins.length) out.admins = admins; else delete out.admins;

            var content;
            try { content = window.jsyaml.dump(out); }
            catch (e2) { err.textContent = 'Could not serialize: ' + (e2.message || e2); return; }

            save.disabled = true;
            save.textContent = 'Saving…';
            var node = { url: zddcUrl, name: '.zddc', ext: '' };
            util.saveFile(node, content, 'application/yaml; charset=utf-8', etag ? { etag: etag } : {})
                .then(function () {
                    toast('Access updated for ' + base, 'success');
                    var ev = app.modules.events;
                    if (ev && ev.refreshListing) { try { ev.refreshListing(); } catch (_e) { /* ignore */ } }
                    close();
                })
                .catch(function (e3) {
                    save.disabled = false;
                    save.textContent = 'Save';
                    if (e3 && e3.status === 412) {
                        err.textContent = 'These rules changed on the server since you opened this. Close and reopen to get the latest, then redo your change.';
                    } else {
                        err.textContent = 'Save failed: ' + (e3 && e3.message ? e3.message : e3);
                    }
                });
        });

        document.body.appendChild(overlay);
        var first = box.querySelector('.ma-who');
        if (first) first.focus();
    }

    app.modules.manageAccess = { open: open };
})(window.app);
