{* DNS Servers page — ONLY type=dns. Driver options: hestiacp or powerdns.
   DNS servers are independent of groups: a single DNS server can be attached
   to many groups via the puqWebHosting_group_dns_servers junction (Group →
   "DNS servers" tab). The legacy puqWebHosting_servers.group_id column is
   ignored for type=dns — no Group field in this form/list. *}
<style>
/* Hide the Group field that's shared with web/mail server modal — DNS
   servers don't use single-group ownership. */
#puq-modal [data-field="group_id"] { display: none !important; }
</style>
<div class="panel panel-default">
    <div class="panel-heading">
        <h3 class="panel-title pull-left"><i class="fa fa-network-wired"></i> DNS Servers</h3>
        <div class="pull-right">
            <select id="puq-filter-driver" class="input-sm" style="margin-right:6px;">
                <option value="">All drivers</option>
                <option value="hestiacp">hestiacp</option>
                <option value="powerdns">powerdns</option>
            </select>
            <button class="btn btn-primary btn-sm" id="puq-add-btn"><i class="fa fa-plus"></i> Add DNS Server</button>
        </div>
        <div class="clearfix"></div>
    </div>
    <div class="panel-body">
        <p class="text-muted small" style="margin-bottom:8px;">
            DNS servers are independent — attach them to groups from
            <strong>Group → DNS servers</strong> tab. One DNS server can serve many groups.
        </p>
        <table class="table table-striped table-bordered" id="puq-data-table" style="width:100%;">
            <thead>
                <tr>
                    <th style="width:50px;">ID</th>
                    <th>Server</th>
                    <th style="width:90px;">Status</th>
                    <th style="width:180px;">Actions</th>
                </tr>
            </thead>
            <tbody><tr><td colspan="4" class="text-center"><i class="fa fa-spinner fa-spin"></i> Loading…</td></tr></tbody>
        </table>
    </div>
</div>

{include file="$dir/templates/_server_modal.tpl"}

{literal}
<script>
(function(){
    var baseUrl = '{/literal}{$meta.admin_module_url}&ajax={literal}';
    var driversByType = { web: ['hestiacp'], mail: ['hestiacp'], dns: ['hestiacp','powerdns'] };
    var editingId = null;

    function healthBadgeInline(state, err){
        var cls = {never:'default',queued:'warning',collecting:'info',ok:'success',error:'danger'}[state]||'default';
        var errIcon = state === 'error' && err ? ' <i class="fa fa-exclamation-triangle" title="'+escAttr(err)+'"></i>' : '';
        return '<span class="label label-'+cls+'">'+esc((state||'never').toUpperCase())+errIcon+'</span>';
    }
    function pctColor(p){
        if (p == null || isNaN(p)) return 'default';
        if (p >= 90) return 'danger';
        if (p >= 75) return 'warning';
        if (p >= 50) return 'info';
        return 'success';
    }
    function metricCell(icon, label, pct, detail){
        if (pct == null) {
            return '<div class="m-cell"><div class="m-label"><i class="fa ' + icon + '"></i>' + esc(label) + '</div>' +
                   '<div class="m-bar"><div style="width:0%"></div></div><div class="m-pct text-muted">—</div></div>';
        }
        var cls   = pctColor(pct);
        var pctI  = Math.min(100, Math.max(0, pct));
        var pctTxt= (pct % 1 === 0 ? pct : pct.toFixed(1)) + '%';
        var title = label + (detail ? ' — ' + detail : '') + ' (' + pctTxt + ')';
        var pctExtra = (cls === 'danger') ? ' m-pct-danger' : (cls === 'warning' ? ' m-pct-warning' : '');
        return '<div class="m-cell" title="' + esc(title) + '">' +
                 '<div class="m-label"><i class="fa ' + icon + '"></i>' + esc(label) + '</div>' +
                 '<div class="m-bar m-bar-' + cls + '"><div style="width:' + pctI + '%"></div></div>' +
                 '<div class="m-pct' + pctExtra + '">' + pctTxt + '</div>' +
               '</div>';
    }

    function load() {
        puqAjax({
            container: '#puq-data-table',
            loadingCaption: 'Loading DNS servers…',
            url: baseUrl + 'listServers&type=dns',
            dataType: 'json',
            success: function(r) {
                var $tbody = $('#puq-data-table tbody').empty();
                if (r.status !== 'success' || !r.data.length) {
                    $tbody.append('<tr><td colspan="4" class="text-center text-muted">No DNS servers yet.</td></tr>');
                    return;
                }
                var driverFilter = $('#puq-filter-driver').val();
                r.data.forEach(function(s) {
                    if (driverFilter && s.driver !== driverFilter) return;
                    var drvLbl = s.driver === 'hestiacp' ? 'info' : s.driver === 'powerdns' ? 'warning' : 'default';
                    var statusLbl = s.status === 'active' ? 'success' : s.status === 'maintenance' ? 'warning' : 'default';
                    var summary = s.status_summary;
                    var summaryTxt = '';
                    if (summary && typeof summary === 'object') {
                        var pills = [];
                        // CPU/RAM/Disk/Load come from Hestia's SSH probe and
                        // don't apply to API-only drivers (PowerDNS). For
                        // those we just show version + zones_count.
                        if (s.driver === 'hestiacp') {
                            var loadPct = (summary.load_1 != null && summary.cpu_cores)
                                ? Math.round(summary.load_1 * 100 / summary.cpu_cores) : null;
                            var loadTxt = (summary.load_1!=null?summary.load_1.toFixed(2):'—') + ' / ' +
                                          (summary.load_5!=null?summary.load_5.toFixed(2):'—') + ' / ' +
                                          (summary.load_15!=null?summary.load_15.toFixed(2):'—') + ' (1/5/15m)';
                            var cells =
                                metricCell('fa-microchip',      'CPU',  summary.cpu_percent,
                                           summary.cpu_cores ? (summary.cpu_cores + ' cores') : null) +
                                metricCell('fa-memory',         'RAM',  summary.mem_percent,
                                           fmtBytes(summary.mem_used) + ' / ' + fmtBytes(summary.mem_total)) +
                                metricCell('fa-hdd',            'Disk', summary.disk_percent,
                                           fmtBytes(summary.disk_used) + ' / ' + fmtBytes(summary.disk_total) +
                                           ' · free ' + fmtBytes(summary.disk_free)) +
                                metricCell('fa-tachometer-alt', 'Load', loadPct, loadTxt);
                            summaryTxt = '<div class="puq-metrics">' + cells + '</div>';
                        }

                        if (summary.version)        pills.push('<span class="pill"><i class="fa fa-code-branch"></i>v' + esc(summary.version) + '</span>');
                        if (summary.hestia_version) pills.push('<span class="pill"><i class="fa fa-code-branch"></i>v' + esc(summary.hestia_version) + '</span>');
                        if (summary.zones_count != null) pills.push('<span class="pill"><i class="fa fa-globe"></i>' + summary.zones_count + ' zones</span>');
                        if (s.driver === 'powerdns') pills.unshift('<span class="pill"><i class="fa fa-server"></i>PowerDNS API</span>');

                        if (pills.length) summaryTxt += '<div class="puq-inventory">' + pills.join('') + '</div>';
                    }
                    var actionsUrl = '{/literal}{$meta.admin_module_url}{literal}&page=server_actions&server_id=' + s.id;

                    var headTs = s.status_last_collected_at
                        ? '<span class="srv-health-ts" title="Last collected">' + esc(s.status_last_collected_at.substring(0,16)) + '</span>'
                        : '';
                    var capsHead = '';
                    [['web', 'caps_web', 'primary'],
                     ['mail', 'caps_mail', 'success'],
                     ['dns', 'caps_dns', 'info']].forEach(function (pair) {
                        var on = parseInt(s[pair[1]] || 0, 10) === 1;
                        capsHead += '<span class="label label-' + (on ? pair[2] : 'default')
                            + '" style="margin-right:2px;opacity:' + (on ? 1 : 0.3) + ';">'
                            + pair[0] + '</span>';
                    });
                    var serverCell =
                        '<div class="puq-server-cell">' +
                          '<div class="srv-head">' +
                            capsHead +
                            '<span class="label label-' + drvLbl + '">' + esc(s.driver) + '</span>' +
                            '<span class="srv-name">' + esc(s.name) + '</span>' +
                            '<span class="srv-host">' + esc(s.hostname) + ':' + s.port + '</span>' +
                            healthBadgeInline(s.status_state, s.status_error) +
                            headTs +
                          '</div>' +
                          summaryTxt +
                        '</div>';

                    $tbody.append(
                        '<tr data-id="' + s.id + '">' +
                        '<td>' + s.id + '</td>' +
                        '<td>' + serverCell + '</td>' +
                        '<td><span class="label label-' + statusLbl + '">' + esc(s.status) + '</span></td>' +
                        '<td>' +
                          '<button class="btn btn-xs btn-info puq-test" title="Test"><i class="fa fa-plug"></i></button> ' +
                          '<button class="btn btn-xs btn-default puq-refresh" title="Refresh status"><i class="fa fa-sync"></i></button> ' +
                          '<a class="btn btn-xs btn-success puq-nav-link" href="' + actionsUrl + '" title="Actions"><i class="fa fa-bolt"></i></a> ' +
                          '<button class="btn btn-xs btn-primary puq-edit"><i class="fa fa-edit"></i></button> ' +
                          '<button class="btn btn-xs btn-danger puq-delete"><i class="fa fa-trash"></i></button>' +
                        '</td></tr>'
                    );
                });
            }
        });
    }

    // No loadGroups: DNS servers don't carry a single-group ownership. The
    // group_id field in the shared modal is hidden via CSS at the top of
    // this template; nothing populates it.
    function refreshDriverDropdown(type, selectedDriver) {
        var drivers = driversByType[type] || ['hestiacp'];
        var $sel = $('#puq-field-driver').empty();
        drivers.forEach(function(d) { $sel.append('<option value="'+d+'">'+d+'</option>'); });
        if (selectedDriver && drivers.indexOf(selectedDriver) !== -1) $sel.val(selectedDriver);
    }
    function renderDriverConfig(type, driver, cfg) {
        $.ajax({
            url: baseUrl + 'getDriverConfigSchema&type=' + encodeURIComponent(type) + '&driver=' + encodeURIComponent(driver),
            dataType: 'json',
            success: function(r) {
                var $host = $('#puq-driver-config').empty();
                var schema = (r.data || {});
                Object.keys(schema).forEach(function(key) {
                    var f = schema[key];
                    var val = (cfg && cfg[key] != null) ? cfg[key] : f.default;
                    var html = '';
                    if (f.type === 'checkbox') {
                        html = '<div class="form-group" data-field="config.' + key + '"><label>' +
                            '<input type="hidden" name="config['+key+']" value="0">' +
                            '<input type="checkbox" name="config['+key+']" value="1" ' + (val ? 'checked' : '') + '> ' +
                            esc(f.label) + '</label>' +
                            (f.help ? '<div class="help-block small">' + esc(f.help) + '</div>' : '') + '</div>';
                    } else if (f.type === 'select') {
                        var opts = '';
                        Object.keys(f.options || {}).forEach(function(k){
                            opts += '<option value="' + esc(k) + '"' + (String(val) === String(k) ? ' selected' : '') + '>' + esc(f.options[k]) + '</option>';
                        });
                        html = '<div class="form-group" data-field="config.' + key + '"><label>' + esc(f.label) + '</label>' +
                            '<select class="form-control" name="config['+key+']" style="max-width:300px">' + opts + '</select>' +
                            (f.help ? '<div class="help-block small">' + esc(f.help) + '</div>' : '') + '</div>';
                    } else {
                        var inputType = f.type === 'number' ? 'number' : 'text';
                        html = '<div class="form-group" data-field="config.' + key + '"><label>' + esc(f.label) + '</label>' +
                            '<input type="' + inputType + '" class="form-control" name="config['+key+']" value="' + esc(val) + '">' +
                            (f.help ? '<div class="help-block small">' + esc(f.help) + '</div>' : '') + '</div>';
                    }
                    $host.append(html);
                });
            }
        });
    }

    function openModal(row) {
        editingId = row ? row.id : null;
        var f = $('#puq-modal-form')[0];
        f.reset();
        formClearErrors('#puq-modal-form');
        $('#puq-field-id').val(row ? row.id : '');
        if (typeof window.puqApplyServerCaps === 'function') window.puqApplyServerCaps(row, 'dns');
        refreshDriverDropdown('dns', row ? row.driver : 'hestiacp');
        $('#puq-field-name').val(row ? row.name : '');
        $('#puq-field-hostname').val(row ? row.hostname : '');
        $('#puq-field-ip').val(row && row.ip ? row.ip : '');
        $('#puq-field-port').val(row ? row.port : 22);
        $('#puq-field-username').val(row && row.username ? row.username : 'root');
        var auth = (row && row.ssh_auth_method) ? row.ssh_auth_method : 'password';
        $('input[name=ssh_auth_method][value='+auth+']').prop('checked', true);
        $('#puq-auth-password-row').toggle(auth === 'password');
        $('#puq-auth-key-row').toggle(auth === 'key');
        $('#puq-field-ssh-password').val('');
        $('#puq-field-ssh-private-key').val('');
        $('#puq-field-ssh-key-passphrase').val('');
        $('#puq-field-status').val(row ? row.status : 'active');
        // group_id is web/mail "ownership" — meaningless for pure-DNS servers
        // and NOT editable from this page. We DISABLE the field so the browser
        // omits it from the submitted form; SaveServer then leaves the stored
        // group_id untouched. This matters for UNIFIED servers (web+mail+dns):
        // editing one here must never wipe the group it owns for its web/mail
        // role. (The field is also hidden via CSS at the top of this template.)
        $('#puq-field-group').val('').prop('disabled', true);
        // Same treatment for the web-only fields inside #puq-web-only
        // (dns_template_id + capacity_max): the DNS page only HIDES that block,
        // and a hidden-but-enabled empty field is still serialized — which would
        // wipe a unified server's zone template / capacity on save. Disable them
        // so they are omitted from the POST and SaveServer preserves stored values.
        $('#puq-field-template, #puq-field-capacity').val('').prop('disabled', true);
        var selectedDriver = $('#puq-field-driver').val();
        renderDriverConfig('dns', selectedDriver, row ? row.config_parsed : null);
        // Driver-conditional field visibility (SSH vs PowerDNS-API). Must run
        // AFTER refreshDriverDropdown so the driver value is final.
        if (typeof window.puqApplyDriverVisibility === 'function') {
            window.puqApplyDriverVisibility(selectedDriver);
        }
        // Clear PowerDNS api-key input — never pre-populate, leave blank means "keep existing".
        $('#puq-field-pdns-api-key').val('');
        $('#puq-web-only').hide(); // never applicable to DNS
        $('#puq-test-btn').toggle(!!row);
        $('#puq-modal-title').text(row ? 'Edit DNS Server' : 'Add DNS Server');
        $('#puq-modal').modal('show');
    }

    $(document).ready(function(){
        load();
        $('#puq-filter-driver').on('change', load);

        $('#puq-field-driver').on('change', function() {
            renderDriverConfig('dns', this.value, null);
            if (typeof window.puqApplyDriverVisibility === 'function') {
                window.puqApplyDriverVisibility(this.value);
            }
        });
        $('#puq-modal').on('change', 'input[name=ssh_auth_method]', function() {
            var v = $('input[name=ssh_auth_method]:checked').val();
            $('#puq-auth-password-row').toggle(v === 'password');
            $('#puq-auth-key-row').toggle(v === 'key');
        });

        $('#puq-add-btn').on('click', function() { openModal(null); });

        $('#puq-data-table').on('click', '.puq-edit', function() {
            var btn = this;
            var id = $(this).closest('tr').data('id');
            btnSpinner(btn);
            $.ajax({
                url: baseUrl + 'getServer&id=' + id, dataType: 'json',
                success: function(r) {
                    if (r.status === 'success') {
                        var row = r.data;
                        try { row.config_parsed = row.config ? JSON.parse(row.config) : {}; } catch(e){ row.config_parsed = {}; }
                        openModal(row);
                    } else {
                        showNotification(r.msg || 'Failed to load.', 'error');
                    }
                },
                error: function() { showNotification('Request failed.', 'error'); },
                complete: function() { btnRestore(btn, 'edit', ''); }
            });
        });

        $('#puq-modal-save').on('click', function() {
            formSubmit({
                btn: this, form: '#puq-modal-form', baseUrl: baseUrl, action: 'saveServer',
                onSuccess: function() { $('#puq-modal').modal('hide'); load(); }
            });
        });

        $('#puq-data-table').on('click', '.puq-delete', function() {
            $('#puq-delete-id').val($(this).closest('tr').data('id'));
            $('#puq-delete-modal').modal('show');
        });

        $('#puq-confirm-delete').on('click', function() {
            var btn = this;
            btnSpinner(btn, 'Deleting...');
            $.ajax({
                url: baseUrl + 'deleteServer', type: 'POST', data: { id: $('#puq-delete-id').val() }, dataType: 'json',
                success: function(r) {
                    if (r.status === 'success') { showNotification(r.msg || 'Server deleted.', 'success'); load(); }
                    else { showNotification(r.msg || 'Delete failed.', 'error'); }
                    $('#puq-delete-modal').modal('hide');
                },
                error: function() { showNotification('Request failed.', 'error'); $('#puq-delete-modal').modal('hide'); },
                complete: function() { btnRestore(btn, 'trash', 'Delete'); }
            });
        });

        $('#puq-data-table').on('click', '.puq-test', function() {
            var btn = this; var id = $(this).closest('tr').data('id');
            btnSpinner(btn);
            $.ajax({
                url: baseUrl + 'testServerConnection', type: 'POST', data: { id: id }, dataType: 'json',
                success: function(r) {
                    if (r.status === 'success') { showNotification('Connection OK — status refresh queued', 'success'); setTimeout(load, 1500); }
                    else showNotification('Connection FAILED: ' + (r.error || r.msg || 'unknown'), 'error');
                },
                error: function() { showNotification('Request failed.', 'error'); },
                complete: function() { btnRestore(btn, 'plug', ''); }
            });
        });

        $('#puq-data-table').on('click', '.puq-refresh', function() {
            var btn = this; var id = $(this).closest('tr').data('id');
            btnSpinner(btn);
            $.ajax({
                url: baseUrl + 'refreshServerStatus', type: 'POST', data: { id: id }, dataType: 'json',
                success: function(r) {
                    if (r.status === 'success') { showNotification(r.msg || 'Refresh queued', 'success'); setTimeout(load, 1500); }
                    else showNotification(r.msg || 'Refresh failed', 'error');
                },
                error: function() { showNotification('Request failed.', 'error'); },
                complete: function() { btnRestore(btn, 'sync', ''); }
            });
        });

        $('#puq-test-btn').on('click', function() {
            if (!editingId) return;
            var btn = this;
            btnSpinner(btn, 'Testing...');
            $.ajax({
                url: baseUrl + 'testServerConnection', type: 'POST', data: { id: editingId }, dataType: 'json',
                success: function(r) {
                    if (r.status === 'success') showNotification('Connection OK', 'success');
                    else showNotification('Connection FAILED: ' + (r.error || r.msg || 'unknown'), 'error');
                },
                error: function() { showNotification('Request failed.', 'error'); },
                complete: function() { btnRestore(btn, 'plug', 'Test connection'); }
            });
        });
    });
})();
</script>
{/literal}
