<style>
.clicd-nat-panel{font-size:14px;color:#1f2937}
.clicd-nat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin-bottom:16px}
.clicd-nat-card{border:1px solid #e5e7eb;border-radius:6px;padding:12px;background:#fff}
.clicd-nat-label{color:#6b7280;font-size:12px;margin-bottom:4px}
.clicd-nat-value{font-size:18px;font-weight:600;word-break:break-all}
.clicd-nat-title{font-weight:600;margin:18px 0 8px}
.clicd-nat-muted{color:#6b7280}
.clicd-nat-form{border:1px solid #e5e7eb;border-radius:6px;background:#fff;padding:12px;margin-top:8px}
.clicd-nat-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;align-items:end}
.clicd-nat-field label{display:block;color:#6b7280;font-size:12px;margin-bottom:4px}
.clicd-nat-input,.clicd-nat-select{width:100%;height:34px;border:1px solid #d1d5db;border-radius:4px;padding:6px 8px;box-sizing:border-box}
.clicd-nat-actions{display:flex;gap:8px;flex-wrap:wrap}
.clicd-nat-btn{height:34px;border:1px solid #2563eb;background:#2563eb;color:#fff;border-radius:4px;padding:0 12px;cursor:pointer}
.clicd-nat-btn[disabled]{opacity:.6;cursor:not-allowed}
.clicd-nat-btn-secondary{border-color:#d1d5db;background:#fff;color:#374151}
.clicd-nat-btn-danger{border-color:#dc2626;background:#dc2626;color:#fff}
.clicd-nat-list{display:flex;flex-direction:column;gap:10px;margin-top:8px}
.clicd-nat-item{border:1px solid #e5e7eb;border-radius:6px;background:#fff;padding:12px}
.clicd-nat-message{border:1px solid #bfdbfe;background:#eff6ff;color:#1d4ed8;border-radius:6px;padding:10px 12px;margin-bottom:12px;display:none}
.clicd-nat-message.error{border-color:#fecaca;background:#fef2f2;color:#b91c1c}
.clicd-nat-debug{margin-top:12px;border:1px dashed #d1d5db;border-radius:6px;background:#f9fafb;padding:10px;color:#374151;white-space:pre-wrap;font-size:12px;display:none}
.clicd-nat-modal-mask{position:fixed;inset:0;background:rgba(15,23,42,.42);display:none;align-items:center;justify-content:center;z-index:9999;padding:16px}
.clicd-nat-modal{width:min(420px,100%);background:#fff;border-radius:6px;border:1px solid #e5e7eb;box-shadow:0 18px 48px rgba(15,23,42,.22);padding:16px}
.clicd-nat-modal-title{font-size:16px;font-weight:700;color:#111827;margin-bottom:8px}
.clicd-nat-modal-body{font-size:14px;color:#4b5563;line-height:1.6;margin-bottom:14px}
.clicd-nat-modal-actions{display:flex;justify-content:flex-end;gap:8px}
</style>

<div class="clicd-nat-panel" id="clicd-nat-panel" data-service-id="{$service_id}" data-area-key="{$area_key}">
    <div class="clicd-nat-message" id="clicd-nat-message"></div>

    <div class="clicd-nat-grid">
        <div class="clicd-nat-card">
            <div class="clicd-nat-label">&#23454;&#20363;&#21517;&#31216;</div>
            <div class="clicd-nat-value">{$container_name}</div>
        </div>
        <div class="clicd-nat-card">
            <div class="clicd-nat-label">&#20844;&#32593;&#22320;&#22336;</div>
            <div class="clicd-nat-value">{$nat_host}</div>
        </div>
        <div class="clicd-nat-card">
            <div class="clicd-nat-label">SSH &#31471;&#21475;</div>
            <div class="clicd-nat-value">{$ssh_port}</div>
        </div>
    </div>

    <div class="clicd-nat-title">&#28155;&#21152;&#31471;&#21475;&#26144;&#23556;</div>
    <div class="clicd-nat-form">
        <div class="clicd-nat-row">
            <div class="clicd-nat-field">
                <label>&#20844;&#32593;&#31471;&#21475;</label>
                <input class="clicd-nat-input" id="clicd-add-host-port" type="number" min="1" max="65535" placeholder="61320">
            </div>
            <div class="clicd-nat-field">
                <label>&#23481;&#22120;&#31471;&#21475;</label>
                <input class="clicd-nat-input" id="clicd-add-container-port" type="number" min="1" max="65535" placeholder="8080">
            </div>
            <div class="clicd-nat-field">
                <label>&#21327;&#35758;</label>
                <select class="clicd-nat-select" id="clicd-add-protocol">
                    <option value="tcp">TCP</option>
                    <option value="udp">UDP</option>
                </select>
            </div>
            <div class="clicd-nat-field">
                <label>&#35828;&#26126;</label>
                <input class="clicd-nat-input" id="clicd-add-description" type="text" placeholder="HTTP">
            </div>
            <div class="clicd-nat-actions">
                <button class="clicd-nat-btn" type="button" data-clicd-action="add">&#28155;&#21152;</button>
                <button class="clicd-nat-btn clicd-nat-btn-secondary" type="button" data-clicd-action="random-port">&#33719;&#21462;&#38543;&#26426;&#31471;&#21475;</button>
            </div>
        </div>
    </div>

    <div class="clicd-nat-title">&#29616;&#26377;&#31471;&#21475;&#26144;&#23556;</div>
    <div id="clicd-nat-list" class="clicd-nat-list">
        {if condition="empty($port_mappings)"}
        <div class="clicd-nat-form clicd-nat-muted">&#26242;&#26080;&#31471;&#21475;&#26144;&#23556;</div>
        {else/}
        {foreach name="port_mappings" item="mapping"}
        <div class="clicd-nat-item" data-index="{$mapping.index}">
            <div class="clicd-nat-row">
                <div class="clicd-nat-field">
                    <label>&#32034;&#24341;</label>
                    <div class="clicd-nat-value">{$mapping.index}</div>
                </div>
                <div class="clicd-nat-field">
                    <label>&#20844;&#32593;&#35775;&#38382;</label>
                    <div class="clicd-nat-value">{$nat_host}:{$mapping.host_port}</div>
                </div>
                <div class="clicd-nat-field">
                    <label>&#20844;&#32593;&#31471;&#21475;</label>
                    <input class="clicd-nat-input" data-field="host_port" type="number" min="1" max="65535" value="{$mapping.host_port}">
                </div>
                <div class="clicd-nat-field">
                    <label>&#23481;&#22120;&#31471;&#21475;</label>
                    <input class="clicd-nat-input" data-field="container_port" type="number" min="1" max="65535" value="{$mapping.container_port}">
                </div>
                <div class="clicd-nat-field">
                    <label>&#21327;&#35758;</label>
                    <select class="clicd-nat-select" data-field="protocol">
                        <option value="tcp" {$mapping.tcp_selected}>TCP</option>
                        <option value="udp" {$mapping.udp_selected}>UDP</option>
                    </select>
                </div>
                <div class="clicd-nat-field">
                    <label>&#35828;&#26126;</label>
                    <input class="clicd-nat-input" data-field="description" type="text" value="{$mapping.description}">
                </div>
                <div class="clicd-nat-actions">
                    <button class="clicd-nat-btn clicd-nat-btn-secondary" type="button" data-clicd-action="update">&#20445;&#23384;</button>
                    <button class="clicd-nat-btn clicd-nat-btn-danger" type="button" data-clicd-action="delete">&#21024;&#38500;</button>
                </div>
            </div>
        </div>
        {/foreach}
        {/if}
    </div>

    <pre class="clicd-nat-debug" id="clicd-nat-debug"></pre>
    <div class="clicd-nat-modal-mask" id="clicd-nat-delete-modal">
        <div class="clicd-nat-modal">
            <div class="clicd-nat-modal-title">&#30830;&#35748;&#21024;&#38500;</div>
            <div class="clicd-nat-modal-body" id="clicd-nat-delete-text">&#30830;&#35748;&#21024;&#38500;&#35813;&#31471;&#21475;&#26144;&#23556;&#65311;</div>
            <div class="clicd-nat-modal-actions">
                <button class="clicd-nat-btn clicd-nat-btn-secondary" type="button" id="clicd-nat-delete-cancel">&#21462;&#28040;</button>
                <button class="clicd-nat-btn clicd-nat-btn-danger" type="button" id="clicd-nat-delete-confirm">&#21024;&#38500;</button>
            </div>
        </div>
    </div>
</div>

<script>
(function(){
    var panel = document.getElementById('clicd-nat-panel');
    if (!panel || panel.getAttribute('data-bound') === '1') return;
    panel.setAttribute('data-bound', '1');

    var message = document.getElementById('clicd-nat-message');
    var debugBox = document.getElementById('clicd-nat-debug');
    var list = document.getElementById('clicd-nat-list');
    var natHost = '{$nat_host}';
    var deleteModal = document.getElementById('clicd-nat-delete-modal');
    var deleteText = document.getElementById('clicd-nat-delete-text');
    var deleteCancel = document.getElementById('clicd-nat-delete-cancel');
    var deleteConfirm = document.getElementById('clicd-nat-delete-confirm');
    var pendingDeletePayload = null;

    function showMessage(type, text) {
        message.className = 'clicd-nat-message' + (type === 'error' ? ' error' : '');
        message.style.display = 'block';
        message.textContent = text || '';
    }

    function showDebug(data) {
        debugBox.style.display = 'block';
        debugBox.textContent = JSON.stringify(data || {}, null, 2);
    }

    function endpoint() {
        return "{$MODULE_CUSTOM_API}";
    }

    function field(item, name) {
        return item.querySelector('[data-field="' + name + '"]');
    }

    function setBusy(busy) {
        panel.querySelectorAll('button').forEach(function(btn){ btn.disabled = !!busy; });
    }

    function renderList(items) {
        if (!Array.isArray(items) || items.length === 0) {
            list.innerHTML = '<div class="clicd-nat-form clicd-nat-muted">&#26242;&#26080;&#31471;&#21475;&#26144;&#23556;</div>';
            return;
        }
        list.innerHTML = items.map(function(item) {
            var protocol = (item.protocol || 'tcp').toLowerCase();
            var desc = escapeHtml(item.description || '');
            var index = escapeHtml(String(item.index));
            var hostPort = escapeHtml(String(item.host_port || ''));
            var containerPort = escapeHtml(String(item.container_port || ''));
            return '<div class="clicd-nat-item" data-index="' + index + '">' +
                '<div class="clicd-nat-row">' +
                '<div class="clicd-nat-field"><label>&#32034;&#24341;</label><div class="clicd-nat-value">' + index + '</div></div>' +
                '<div class="clicd-nat-field"><label>&#20844;&#32593;&#35775;&#38382;</label><div class="clicd-nat-value">' + escapeHtml(natHost) + ':' + hostPort + '</div></div>' +
                '<div class="clicd-nat-field"><label>&#20844;&#32593;&#31471;&#21475;</label><input class="clicd-nat-input" data-field="host_port" type="number" min="1" max="65535" value="' + hostPort + '"></div>' +
                '<div class="clicd-nat-field"><label>&#23481;&#22120;&#31471;&#21475;</label><input class="clicd-nat-input" data-field="container_port" type="number" min="1" max="65535" value="' + containerPort + '"></div>' +
                '<div class="clicd-nat-field"><label>&#21327;&#35758;</label><select class="clicd-nat-select" data-field="protocol">' +
                '<option value="tcp"' + (protocol === 'tcp' ? ' selected' : '') + '>TCP</option>' +
                '<option value="udp"' + (protocol === 'udp' ? ' selected' : '') + '>UDP</option>' +
                '</select></div>' +
                '<div class="clicd-nat-field"><label>&#35828;&#26126;</label><input class="clicd-nat-input" data-field="description" type="text" value="' + desc + '"></div>' +
                '<div class="clicd-nat-actions"><button class="clicd-nat-btn clicd-nat-btn-secondary" type="button" data-clicd-action="update">&#20445;&#23384;</button>' +
                '<button class="clicd-nat-btn clicd-nat-btn-danger" type="button" data-clicd-action="delete">&#21024;&#38500;</button></div>' +
                '</div></div>';
        }).join('');
    }

    function escapeHtml(value) {
        return String(value)
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#039;');
    }

    async function request(action, payload, silent) {
        setBusy(true);
        try {
            var funcMap = {
                'random-port': 'randomPort',
                'add': 'addNat',
                'update': 'updateNat',
                'delete': 'deleteNat',
                'list': 'natList'
            };
            var body = new URLSearchParams();
            body.set('id', panel.getAttribute('data-service-id') || '');
            body.set('func', funcMap[action] || action);
            Object.keys(payload || {}).forEach(function(key){ body.set(key, payload[key]); });
            var res = await fetch(endpoint(), {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                    'Authorization': 'JWT {$Think.get.jwt}'
                },
                credentials: 'same-origin',
                body: body.toString()
            });
            var text = await res.text();
            var data;
            try { data = JSON.parse(text); } catch (e) { data = {status:'error', msg:'\u975e JSON \u54cd\u5e94: ' + text}; }
            showDebug((data.data && data.data.debug) || data.debug || data);
            if (data.status === 200 || data.status === 'success') {
                if (!silent) {
                    showMessage('success', data.msg || '\u64cd\u4f5c\u6210\u529f');
                }
                if (data.data && data.data.port) {
                    document.getElementById('clicd-add-host-port').value = data.data.port;
                }
                if (data.data && Array.isArray(data.data.port_mappings)) {
                    renderList(data.data.port_mappings);
                } else if (action !== 'random-port') {
                    request('list', {}, true);
                }
            } else {
                showMessage('error', data.msg || '\u64cd\u4f5c\u5931\u8d25');
            }
        } catch (e) {
            showMessage('error', e.message || '\u8bf7\u6c42\u5931\u8d25');
            showDebug({error: String(e)});
        } finally {
            setBusy(false);
        }
    }

    function openDeleteModal(payload) {
        pendingDeletePayload = payload;
        if (deleteText) {
            deleteText.textContent = '\u786e\u8ba4\u5220\u9664\u7aef\u53e3\u6620\u5c04 ' + natHost + ':' + (payload.host_port || '-') + ' -> ' + (payload.container_port || '-') + '/' + (payload.protocol || 'tcp') + ' \u5417\uff1f';
        }
        if (deleteModal) {
            deleteModal.style.display = 'flex';
        }
    }

    function closeDeleteModal() {
        pendingDeletePayload = null;
        if (deleteModal) {
            deleteModal.style.display = 'none';
        }
    }

    panel.addEventListener('click', function(event) {
        var button = event.target.closest('[data-clicd-action]');
        if (!button) return;
        var action = button.getAttribute('data-clicd-action');
        if (action === 'random-port') {
            request('random-port', {});
            return;
        }
        if (action === 'add') {
            request('add', {
                host_port: document.getElementById('clicd-add-host-port').value,
                container_port: document.getElementById('clicd-add-container-port').value,
                protocol: document.getElementById('clicd-add-protocol').value,
                description: document.getElementById('clicd-add-description').value
            });
            return;
        }
        var item = button.closest('.clicd-nat-item');
        if (!item) return;
        var payload = {
            index: item.getAttribute('data-index'),
            host_port: field(item, 'host_port') ? field(item, 'host_port').value : '',
            container_port: field(item, 'container_port') ? field(item, 'container_port').value : '',
            protocol: field(item, 'protocol') ? field(item, 'protocol').value : 'tcp',
            description: field(item, 'description') ? field(item, 'description').value : ''
        };
        if (action === 'delete') {
            openDeleteModal(payload);
            return;
        }
        request(action, payload);
    });

    if (deleteCancel) {
        deleteCancel.addEventListener('click', closeDeleteModal);
    }
    if (deleteModal) {
        deleteModal.addEventListener('click', function(event){
            if (event.target === deleteModal) closeDeleteModal();
        });
    }
    if (deleteConfirm) {
        deleteConfirm.addEventListener('click', function(){
            if (!pendingDeletePayload) return;
            var payload = pendingDeletePayload;
            closeDeleteModal();
            request('delete', payload);
        });
    }
})();
</script>
