<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>交易所配置 - OpenClaw</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            background: #0f1419;
            color: #e6e6e6;
            line-height: 1.6;
        }

        .header {
            background: linear-gradient(135deg, #1a2332 0%, #0f1419 100%);
            padding: 20px 30px;
            border-bottom: 1px solid #2d3a4a;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .header h1 {
            font-size: 24px;
            font-weight: 600;
            color: #00d4aa;
        }

        .nav-links {
            display: flex;
            gap: 20px;
        }

        .nav-link {
            color: #8b9aad;
            text-decoration: none;
            font-size: 14px;
            padding: 8px 16px;
            border-radius: 6px;
            transition: all 0.2s;
            display: flex;
            align-items: center;
            gap: 6px;
        }

        .nav-link:hover {
            color: #e6e6e6;
            background: #2d3a4a;
        }

        .nav-link.active {
            color: #00d4aa;
            background: rgba(0, 212, 170, 0.1);
        }

        .container {
            padding: 20px 30px;
            max-width: 1400px;
            margin: 0 auto;
        }

        .page-header {
            margin-bottom: 25px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .page-header h2 {
            font-size: 20px;
            font-weight: 600;
            color: #fff;
            margin-bottom: 8px;
        }

        .page-header p {
            color: #8b9aad;
            font-size: 14px;
        }

        .btn {
            padding: 10px 20px;
            border-radius: 8px;
            font-size: 14px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s;
            border: none;
            display: inline-flex;
            align-items: center;
            gap: 8px;
        }

        .btn:disabled {
            opacity: 0.6;
            cursor: not-allowed;
        }

        .btn-primary {
            background: #00d4aa;
            color: #0f1419;
        }

        .btn-primary:hover:not(:disabled) {
            background: #00e6b8;
            box-shadow: 0 4px 15px rgba(0, 212, 170, 0.3);
        }

        .btn-secondary {
            background: #2d3a4a;
            color: #e6e6e6;
        }

        .btn-secondary:hover:not(:disabled) {
            background: #3d4a5a;
        }

        .btn-danger {
            background: #ff4444;
            color: #fff;
        }

        .btn-danger:hover:not(:disabled) {
            background: #ff5555;
        }

        .btn-success {
            background: #00d4aa;
            color: #0f1419;
        }

        .btn-sm {
            padding: 6px 12px;
            font-size: 12px;
        }

        .exchanges-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
            gap: 20px;
        }

        .exchange-card {
            background: #1a2332;
            border-radius: 12px;
            border: 1px solid #2d3a4a;
            overflow: hidden;
            transition: border-color 0.2s, transform 0.2s;
        }

        .exchange-card:hover {
            border-color: #3d4a5a;
        }

        .exchange-card.disabled {
            opacity: 0.6;
        }

        .exchange-header {
            background: #222d3d;
            padding: 15px 20px;
            border-bottom: 1px solid #2d3a4a;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .exchange-title {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .exchange-icon {
            width: 32px;
            height: 32px;
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: 600;
            font-size: 14px;
        }

        .exchange-icon.binance { background: #f0b90b; color: #000; }
        .exchange-icon.binance_us { background: #f0b90b; color: #000; }
        .exchange-icon.coinbase { background: #0052ff; color: #fff; }
        .exchange-icon.kraken { background: #5741d9; color: #fff; }
        .exchange-icon.bybit { background: #f7a600; color: #000; }
        .exchange-icon.okx { background: #000; color: #fff; border: 1px solid #333; }
        .exchange-icon.gateio { background: #de5959; color: #fff; }
        .exchange-icon.kucoin { background: #01bc8d; color: #fff; }
        .exchange-icon.mexc { background: #00d4aa; color: #000; }
        .exchange-icon.htx { background: #2e5a9c; color: #fff; }

        .exchange-name {
            font-size: 16px;
            font-weight: 600;
            color: #fff;
        }

        .exchange-type {
            font-size: 12px;
            color: #8b9aad;
        }

        .exchange-status {
            display: flex;
            align-items: center;
            gap: 6px;
            font-size: 12px;
            padding: 4px 10px;
            border-radius: 20px;
        }

        .status-enabled {
            background: rgba(0, 212, 170, 0.15);
            color: #00d4aa;
        }

        .status-disabled {
            background: rgba(255, 68, 68, 0.15);
            color: #ff4444;
        }

        .exchange-body {
            padding: 20px;
        }

        .info-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 12px;
            font-size: 14px;
        }

        .info-row:last-child {
            margin-bottom: 0;
        }

        .info-label {
            color: #8b9aad;
        }

        .info-value {
            color: #e6e6e6;
            font-family: monospace;
        }

        .testnet-badge {
            background: #ffc107;
            color: #000;
            padding: 2px 8px;
            border-radius: 4px;
            font-size: 11px;
            font-weight: 600;
        }

        .exchange-actions {
            padding: 15px 20px;
            background: #222d3d;
            display: flex;
            gap: 10px;
            justify-content: flex-end;
        }

        .connection-status {
            display: flex;
            align-items: center;
            gap: 6px;
            font-size: 12px;
        }

        .status-dot {
            width: 8px;
            height: 8px;
            border-radius: 50%;
        }

        .status-dot.connected {
            background: #00d4aa;
            box-shadow: 0 0 8px #00d4aa;
        }

        .status-dot.disconnected {
            background: #ff4444;
        }

        .status-dot.testing {
            background: #ffc107;
            animation: pulse 1s infinite;
        }

        @keyframes pulse {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.5; }
        }

        /* Modal styles */
        .modal-overlay {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0, 0, 0, 0.7);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 1000;
            opacity: 0;
            visibility: hidden;
            transition: all 0.2s;
        }

        .modal-overlay.active {
            opacity: 1;
            visibility: visible;
        }

        .modal {
            background: #1a2332;
            border-radius: 12px;
            width: 90%;
            max-width: 500px;
            max-height: 90vh;
            overflow: hidden;
            transform: scale(0.9);
            transition: transform 0.2s;
        }

        .modal-overlay.active .modal {
            transform: scale(1);
        }

        .modal-header {
            padding: 20px;
            border-bottom: 1px solid #2d3a4a;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .modal-title {
            font-size: 18px;
            font-weight: 600;
            color: #fff;
        }

        .modal-close {
            background: none;
            border: none;
            color: #8b9aad;
            font-size: 24px;
            cursor: pointer;
            padding: 0;
            width: 32px;
            height: 32px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 6px;
            transition: all 0.2s;
        }

        .modal-close:hover {
            color: #fff;
            background: #2d3a4a;
        }

        .modal-body {
            padding: 20px;
            overflow-y: auto;
            max-height: 60vh;
        }

        .modal-footer {
            padding: 15px 20px;
            border-top: 1px solid #2d3a4a;
            display: flex;
            justify-content: flex-end;
            gap: 10px;
        }

        .form-group {
            margin-bottom: 18px;
        }

        .form-group:last-child {
            margin-bottom: 0;
        }

        .form-label {
            display: block;
            font-size: 13px;
            font-weight: 500;
            color: #8b9aad;
            margin-bottom: 6px;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        .form-input {
            width: 100%;
            padding: 10px 14px;
            background: #0f1419;
            border: 1px solid #2d3a4a;
            border-radius: 8px;
            color: #e6e6e6;
            font-size: 14px;
            transition: all 0.2s;
        }

        .form-input:focus {
            outline: none;
            border-color: #00d4aa;
            box-shadow: 0 0 0 3px rgba(0, 212, 170, 0.1);
        }

        .form-input::placeholder {
            color: #5a6a7a;
        }

        select.form-input {
            cursor: pointer;
            appearance: none;
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%238b9aad' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
            background-repeat: no-repeat;
            background-position: right 14px center;
            padding-right: 36px;
        }

        .form-hint {
            font-size: 12px;
            color: #5a6a7a;
            margin-top: 4px;
        }

        .form-error {
            font-size: 12px;
            color: #ff4444;
            margin-top: 4px;
            display: none;
        }

        .form-group.has-error .form-input {
            border-color: #ff4444;
        }

        .form-group.has-error .form-error {
            display: block;
        }

        .checkbox-group {
            display: flex;
            align-items: center;
            gap: 10px;
            cursor: pointer;
        }

        .checkbox-group input[type="checkbox"] {
            width: 18px;
            height: 18px;
            accent-color: #00d4aa;
            cursor: pointer;
        }

        .checkbox-label {
            color: #e6e6e6;
            font-size: 14px;
        }

        .alert-container {
            position: fixed;
            top: 80px;
            right: 20px;
            width: 350px;
            z-index: 1001;
        }

        .alert {
            background: #1a2332;
            border-radius: 10px;
            padding: 15px;
            margin-bottom: 10px;
            border-left: 4px solid;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
            animation: slideIn 0.3s ease-out;
        }

        @keyframes slideIn {
            from { transform: translateX(100%); opacity: 0; }
            to { transform: translateX(0); opacity: 1; }
        }

        .alert-success { border-color: #00d4aa; }
        .alert-error { border-color: #ff4444; }
        .alert-warning { border-color: #ffc107; }

        .alert-title {
            font-weight: 600;
            margin-bottom: 5px;
            color: #fff;
        }

        .alert-message {
            font-size: 13px;
            color: #8b9aad;
        }

        .empty-state {
            text-align: center;
            padding: 60px 20px;
            background: #1a2332;
            border-radius: 12px;
            border: 2px dashed #2d3a4a;
        }

        .empty-state-icon {
            font-size: 48px;
            margin-bottom: 20px;
        }

        .empty-state-title {
            font-size: 18px;
            font-weight: 600;
            color: #fff;
            margin-bottom: 10px;
        }

        .empty-state-text {
            color: #8b9aad;
            font-size: 14px;
            margin-bottom: 20px;
        }

        .warning-box {
            background: rgba(255, 193, 7, 0.1);
            border: 1px solid rgba(255, 193, 7, 0.3);
            border-radius: 8px;
            padding: 12px;
            margin-bottom: 20px;
            display: flex;
            align-items: flex-start;
            gap: 10px;
        }

        .warning-box-icon {
            color: #ffc107;
            font-size: 18px;
        }

        .warning-box-text {
            font-size: 13px;
            color: #e6e6e6;
            line-height: 1.5;
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>🦀 OpenClaw 交易仪表盘</h1>
        <div class="nav-links" style="display: flex; gap: 20px; align-items: center;">
            <a href="/" style="color: #8b9aad; text-decoration: none; font-weight: 500;">仪表盘</a>
            <a href="/orders" style="color: #8b9aad; text-decoration: none; font-weight: 500;">订单</a>
            <a href="/config" style="color: #8b9aad; text-decoration: none; font-weight: 500;">配置</a>
            <a href="/exchanges" style="color: #00d4aa; text-decoration: none; font-weight: 500;">交易所</a>
        </div>
        <div class="connection-status">
            <span class="status-dot" id="statusDot"></span>
            <span id="statusText">连接中...</span>
        </div>
    </div>

    <div class="alert-container" id="alertContainer"></div>

    <div class="container">
        <div class="page-header">
            <div>
                <h2>交易所配置</h2>
                <p>管理交易所 API 密钥和连接设置。</p>
            </div>
            <button class="btn btn-primary" onclick="openAddModal()">
                <span>+ 添加交易所</span>
            </button>
        </div>

        <div id="exchangesContainer">
            <div class="empty-state">
                <div class="empty-state-icon">🏦</div>
                <div class="empty-state-title">暂无交易所配置</div>
                <div class="empty-state-text">点击上方按钮添加您的第一个交易所配置</div>
            </div>
        </div>
    </div>

    <!-- Add/Edit Modal -->
    <div class="modal-overlay" id="exchangeModal">
        <div class="modal">
            <div class="modal-header">
                <div class="modal-title" id="modalTitle">添加交易所</div>
                <button class="modal-close" onclick="closeModal()">&times;</button>
            </div>
            <div class="modal-body">
                <div class="warning-box">
                    <span class="warning-box-icon">⚠️</span>
                    <div class="warning-box-text">
                        API 密钥将通过 OPENCLAW_EXCHANGE_KEY 环境变量加密存储。请确保该环境变量已设置，否则无法安全保存凭证。
                    </div>
                </div>
                <form id="exchangeForm">
                    <input type="hidden" id="configId" value="">

                    <div class="form-group">
                        <label class="form-label" for="exchange">交易所</label>
                        <select id="exchange" class="form-input" required>
                            <option value="">选择交易所...</option>
                            <option value="binance">Binance</option>
                            <option value="binance_us">Binance US</option>
                            <option value="coinbase">Coinbase</option>
                            <option value="kraken">Kraken</option>
                            <option value="bybit">Bybit</option>
                            <option value="okx">OKX</option>
                            <option value="gateio">Gate.io</option>
                            <option value="kucoin">KuCoin</option>
                            <option value="mexc">MEXC</option>
                            <option value="htx">HTX</option>
                        </select>
                    </div>

                    <div class="form-group">
                        <label class="form-label" for="name">显示名称</label>
                        <input type="text" id="name" class="form-input" placeholder="例如：我的 Binance 账户">
                        <div class="form-hint">用于区分多个同一交易所的账户</div>
                    </div>

                    <div class="form-group">
                        <label class="form-label" for="apiKey">API Key</label>
                        <input type="text" id="apiKey" class="form-input" required placeholder="输入您的 API Key">
                    </div>

                    <div class="form-group">
                        <label class="form-label" for="secret">API Secret</label>
                        <input type="password" id="secret" class="form-input" required placeholder="输入您的 API Secret">
                    </div>

                    <div class="form-group">
                        <label class="form-label" for="passphrase">Passphrase（可选）</label>
                        <input type="password" id="passphrase" class="form-input" placeholder="部分交易所需要，如 OKX、Coinbase">
                        <div class="form-hint">仅 OKX 和 Coinbase 等部分交易所需要</div>
                    </div>

                    <div class="form-group">
                        <label class="checkbox-group">
                            <input type="checkbox" id="testnet">
                            <span class="checkbox-label">使用测试网（Sandbox）</span>
                        </label>
                    </div>
                </form>
            </div>
            <div class="modal-footer">
                <button class="btn btn-secondary" onclick="closeModal()">取消</button>
                <button class="btn btn-primary" id="saveBtn" onclick="saveExchange()">保存</button>
            </div>
        </div>
    </div>

    <script>
        let exchanges = {};
        let editingId = null;

        // Initialize
        document.addEventListener('DOMContentLoaded', function() {
            loadExchanges();
        });

        // Load exchanges from server
        function loadExchanges() {
            fetch('/api/exchanges')
                .then(response => response.json())
                .then(data => {
                    exchanges = data;
                    renderExchanges();
                })
                .catch(error => {
                    showAlert('错误', '加载交易所配置失败', 'error');
                });
        }

        // Render exchanges grid
        function renderExchanges() {
            const container = document.getElementById('exchangesContainer');
            const ids = Object.keys(exchanges);

            if (ids.length === 0) {
                container.innerHTML = `
                    <div class="empty-state">
                        <div class="empty-state-icon">🏦</div>
                        <div class="empty-state-title">暂无交易所配置</div>
                        <div class="empty-state-text">点击上方按钮添加您的第一个交易所配置</div>
                    </div>
                `;
                return;
            }

            let html = '<div class="exchanges-grid">';
            for (const id of ids) {
                const config = exchanges[id];
                const exchangeClass = config.exchange.toLowerCase();
                const isEnabled = config.enabled !== false;

                html += `
                    <div class="exchange-card ${isEnabled ? '' : 'disabled'}">
                        <div class="exchange-header">
                            <div class="exchange-title">
                                <div class="exchange-icon ${exchangeClass}">${getExchangeInitial(config.exchange)}</div>
                                <div>
                                    <div class="exchange-name">${escapeHtml(config.name || config.exchange)}</div>
                                    <div class="exchange-type">${config.exchange.toUpperCase()}</div>
                                </div>
                            </div>
                            <span class="exchange-status ${isEnabled ? 'status-enabled' : 'status-disabled'}">
                                ${isEnabled ? '已启用' : '已禁用'}
                            </span>
                        </div>
                        <div class="exchange-body">
                            <div class="info-row">
                                <span class="info-label">API Key</span>
                                <span class="info-value">${maskString(config.api_key)}</span>
                            </div>
                            <div class="info-row">
                                <span class="info-label">环境</span>
                                <span class="info-value">
                                    ${config.testnet ? '<span class="testnet-badge">测试网</span>' : '实盘'}
                                </span>
                            </div>
                            <div class="info-row">
                                <span class="info-label">连接状态</span>
                                <span class="info-value connection-status" id="status-${id}">
                                    <span class="status-dot disconnected"></span>
                                    未测试
                                </span>
                            </div>
                        </div>
                        <div class="exchange-actions">
                            <button class="btn btn-secondary btn-sm" onclick="testConnection('${id}')">
                                测试连接
                            </button>
                            <button class="btn btn-secondary btn-sm" onclick="editExchange('${id}')">
                                编辑
                            </button>
                            <button class="btn btn-danger btn-sm" onclick="deleteExchange('${id}')">
                                删除
                            </button>
                        </div>
                    </div>
                `;
            }
            html += '</div>';
            container.innerHTML = html;
        }

        // Escape HTML to prevent XSS
        function escapeHtml(text) {
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }

        // Get exchange initial
        function getExchangeInitial(exchange) {
            const map = {
                'binance': 'B',
                'binance_us': 'B',
                'coinbase': 'C',
                'kraken': 'K',
                'bybit': 'BB',
                'okx': 'O',
                'gateio': 'G',
                'kucoin': 'K',
                'mexc': 'M',
                'htx': 'H'
            };
            return map[exchange] || exchange[0].toUpperCase();
        }

        // Mask string
        function maskString(str) {
            if (!str || str.length < 8) return '****';
            return str.slice(0, 4) + '****' + str.slice(-4);
        }

        // Open add modal
        function openAddModal() {
            editingId = null;
            document.getElementById('modalTitle').textContent = '添加交易所';
            document.getElementById('exchangeForm').reset();
            document.getElementById('configId').value = '';
            document.getElementById('exchangeModal').classList.add('active');
        }

        // Edit exchange
        function editExchange(id) {
            editingId = id;
            const config = exchanges[id];
            document.getElementById('modalTitle').textContent = '编辑交易所';
            document.getElementById('exchange').value = config.exchange;
            document.getElementById('name').value = config.name || '';
            document.getElementById('apiKey').value = config.api_key;
            document.getElementById('secret').value = config.secret;
            document.getElementById('passphrase').value = config.passphrase || '';
            document.getElementById('testnet').checked = config.testnet || false;
            document.getElementById('configId').value = id;
            document.getElementById('exchangeModal').classList.add('active');
        }

        // Close modal
        function closeModal() {
            document.getElementById('exchangeModal').classList.remove('active');
        }

        // Save exchange
        function saveExchange() {
            const exchange = document.getElementById('exchange').value;
            const name = document.getElementById('name').value;
            const apiKey = document.getElementById('apiKey').value;
            const secret = document.getElementById('secret').value;
            const passphrase = document.getElementById('passphrase').value;
            const testnet = document.getElementById('testnet').checked;

            if (!exchange || !apiKey || !secret) {
                showAlert('错误', '请填写所有必填字段', 'error');
                return;
            }

            const data = {
                exchange: exchange,
                name: name,
                api_key: apiKey,
                secret: secret,
                passphrase: passphrase || null,
                testnet: testnet
            };

            const url = editingId ? '/api/exchanges/' + editingId : '/api/exchanges';
            const method = editingId ? 'PUT' : 'POST';

            fetch(url, {
                method: method,
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(data)
            })
            .then(response => response.json())
            .then(result => {
                if (result.success) {
                    showAlert('成功', editingId ? '交易所配置已更新' : '交易所配置已添加', 'success');
                    closeModal();
                    loadExchanges();
                } else {
                    showAlert('错误', result.message || '保存失败', 'error');
                }
            })
            .catch(error => {
                showAlert('错误', '保存失败: ' + error.message, 'error');
            });
        }

        // Test connection
        function testConnection(id) {
            const statusEl = document.getElementById('status-' + id);
            statusEl.innerHTML = '<span class="status-dot testing"></span> 测试中...';

            fetch('/api/exchanges/' + id + '/test', { method: 'POST' })
                .then(response => response.json())
                .then(result => {
                    if (result.success) {
                        statusEl.innerHTML = '<span class="status-dot connected"></span> 连接成功';
                        showAlert('连接成功', result.message, 'success');
                    } else {
                        statusEl.innerHTML = '<span class="status-dot disconnected"></span> 连接失败';
                        showAlert('连接失败', result.message, 'error');
                    }
                })
                .catch(error => {
                    statusEl.innerHTML = '<span class="status-dot disconnected"></span> 连接失败';
                    showAlert('错误', '测试连接时发生错误', 'error');
                });
        }

        // Delete exchange
        function deleteExchange(id) {
            if (!confirm('确定要删除此交易所配置吗？此操作不可撤销。')) {
                return;
            }

            fetch('/api/exchanges/' + id, { method: 'DELETE' })
                .then(response => response.json())
                .then(result => {
                    if (result.success) {
                        showAlert('成功', '交易所配置已删除', 'success');
                        loadExchanges();
                    } else {
                        showAlert('错误', result.message || '删除失败', 'error');
                    }
                })
                .catch(error => {
                    showAlert('错误', '删除失败: ' + error.message, 'error');
                });
        }

        // Show alert
        function showAlert(title, message, level) {
            const container = document.getElementById('alertContainer');
            const alert = document.createElement('div');
            alert.className = 'alert alert-' + level;
            alert.innerHTML = '<div class="alert-title">' + escapeHtml(title) + '</div>' +
                '<div class="alert-message">' + escapeHtml(message) + '</div>';
            container.appendChild(alert);

            setTimeout(function() {
                alert.style.animation = 'slideIn 0.3s ease-out reverse';
                setTimeout(function() { alert.remove(); }, 300);
            }, 5000);
        }
    </script>
</body>
</html>
