// ============================================
// TAIRUMA APP v3.1 — Premium Experience
// ============================================

// --- Configuration ---
const DEFAULT_API = window.location.origin + '/api';
let API_URL = localStorage.getItem('tairuma_api_url') || DEFAULT_API;
let CURRENT_ALIAS = localStorage.getItem('tairuma_alias');
let CURRENT_SEED = localStorage.getItem('tairuma_seed');
let MY_ZONE = 'Bosque Profundo';
let CHAT_CONTEXT = { type: 'global', id: 'global', name: 'Bosque Global' };
let MARKET_FILTER = 'global';
let ALL_GROUPS_CACHE = [];
let _dashboardInterval = null;

// ============================================
// TOAST NOTIFICATION SYSTEM
// ============================================
const TOAST_ICONS = {
    success: '✅',
    error: '❌',
    warning: '⚠️',
    info: 'ℹ️'
};

function showToast(message, type = 'info', duration = 3000) {
    const container = document.getElementById('toast-container');
    if (!container) return;

    const toast = document.createElement('div');
    toast.className = `toast ${type}`;
    toast.innerHTML = `
        <span class="toast-icon">${TOAST_ICONS[type] || TOAST_ICONS.info}</span>
        <span class="toast-msg">${message}</span>
        <button class="toast-close" onclick="this.parentElement.remove()">✕</button>
    `;

    container.appendChild(toast);

    setTimeout(() => {
        toast.classList.add('removing');
        setTimeout(() => toast.remove(), 300);
    }, duration);
}

// ============================================
// API FETCH WRAPPER (Centralized Error Handling)
// ============================================
async function apiFetch(endpoint, options = {}, retries = 1) {
    const url = endpoint.startsWith('http') ? endpoint : `${API_URL}${endpoint}`;

    // Auto-attach JWT token if available
    const token = localStorage.getItem('tairuma_token');
    if (token) {
        options.headers = options.headers || {};
        if (!options.headers['Authorization']) {
            options.headers['Authorization'] = `Bearer ${token}`;
        }
    }

    for (let attempt = 0; attempt <= retries; attempt++) {
        try {
            const controller = new AbortController();
            const timeoutId = setTimeout(() => controller.abort(), 8000);

            const res = await fetch(url, { ...options, signal: controller.signal });
            clearTimeout(timeoutId);

            if (!res.ok) {
                const errData = await res.json().catch(() => ({}));
                throw new Error(errData.detail || `Error ${res.status}`);
            }
            return res;
        } catch (err) {
            if (attempt === retries) {
                // If it's a network error (not a server error), try failover
                if (err.name === 'AbortError' || err.name === 'TypeError') {
                    if (typeof failoverToNextNode === 'function' && KNOWN_NODES?.length > 1) {
                        await failoverToNextNode();
                        // Retry with new node
                        const newUrl = endpoint.startsWith('http') ? endpoint : `${API_URL}${endpoint}`;
                        try {
                            const res = await fetch(newUrl, { ...options, signal: AbortSignal.timeout(8000) });
                            if (res.ok) return res;
                        } catch (e) { }
                    }
                }
                if (err.name === 'AbortError') {
                    throw new Error('Tiempo de espera agotado');
                }
                throw err;
            }
            // Wait before retry
            await new Promise(r => setTimeout(r, 1000));
        }
    }
}

// ============================================
// OFFLINE / ONLINE DETECTION
// ============================================
function setupConnectivityListeners() {
    const banner = document.getElementById('offline-banner');
    const statusDot = document.getElementById('connection-status');

    window.addEventListener('offline', () => {
        banner?.classList.add('visible');
        statusDot?.classList.remove('online');
        statusDot?.classList.add('offline');
        showToast('Conexión perdida. Trabajando sin red...', 'warning');
    });

    window.addEventListener('online', () => {
        banner?.classList.remove('visible');
        statusDot?.classList.remove('offline');
        statusDot?.classList.add('online');
        showToast('¡Reconectado al Bosque!', 'success');
        // Refresh data on reconnect
        loadDashboardData();
    });
}

// ============================================
// NATURE AVATAR GENERATOR
// ============================================
function getNatureAvatar(seed) {
    if (!seed) return '🌱';
    const icons = ['🌿', '🍄', '🌵', '🌻', '🌲', '🦋', '🐝', '🐞', '🦉', '🦊', '🐻', '🐺', '🐸', '🐢', '🦅', '🦆', '🐚', '🕸️', '🍁', '🪵'];
    let hash = 0;
    for (let i = 0; i < seed.length; i++) hash = seed.charCodeAt(i) + ((hash << 5) - hash);
    return icons[Math.abs(hash) % icons.length];
}

// ============================================
// SKELETON LOADING HELPERS
// ============================================
function showBalanceSkeleton() {
    const balanceEl = document.getElementById('balance');
    if (balanceEl && balanceEl.textContent === '--.--') {
        balanceEl.innerHTML = '<span class="skeleton skeleton-text large" style="display:inline-block; width:120px; height:40px;"></span>';
    }
}

function showListSkeleton(containerId, count = 3) {
    const el = document.getElementById(containerId);
    if (!el) return;
    el.innerHTML = Array(count).fill('<div class="skeleton skeleton-card"></div>').join('');
}

// ============================================
// P2P MULTI-NODE DISCOVERY
// ============================================
let KNOWN_NODES = [];   // [{url, latency, alive, version}]
let PRIMARY_NODE = null;
let _discoveryInterval = null;

async function pingNode(nodeUrl) {
    const cleanUrl = nodeUrl.replace(/\/+$/, '');
    try {
        const start = performance.now();
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), 3000);
        const res = await fetch(`${cleanUrl}/api/p2p/heartbeat`, { signal: controller.signal });
        clearTimeout(timeoutId);
        if (res.ok) {
            const data = await res.json();
            const latency = Math.round(performance.now() - start);
            return { url: cleanUrl, latency, alive: true, version: data.version || '?', alias: data.alias || '' };
        }
    } catch (e) { /* unreachable */ }
    return { url: cleanUrl, latency: Infinity, alive: false, version: '?', alias: '' };
}

async function discoverNodes() {
    // 1. Gather seed URLs from multiple sources
    const seedUrls = new Set();

    // From localStorage (last known good nodes)
    try {
        const saved = JSON.parse(localStorage.getItem('tairuma_known_nodes') || '[]');
        saved.forEach(n => seedUrls.add(n));
    } catch (e) { }

    // From seeds file (bootstrap)
    for (const path of ['nodes.json', '../seed_nodes.json', 'seed_nodes.json']) {
        try {
            const res = await fetch(path);
            if (res.ok) {
                const data = await res.json();
                if (Array.isArray(data)) data.forEach(n => seedUrls.add(n));
            }
        } catch (e) { }
    }

    // Always try the current page's origin first
    seedUrls.add(window.location.origin);

    // Also try localhost as fallback
    seedUrls.add('http://localhost:9500');
    seedUrls.add('http://127.0.0.1:9500');

    // From current API_URL
    if (API_URL && !API_URL.endsWith('/api')) {
        seedUrls.add(API_URL);
    } else if (API_URL) {
        seedUrls.add(API_URL.replace(/\/api$/, ''));
    }

    // 2. Ping ALL seeds in parallel
    const results = await Promise.allSettled(
        [...seedUrls].map(url => pingNode(url))
    );

    const aliveNodes = results
        .filter(r => r.status === 'fulfilled' && r.value.alive)
        .map(r => r.value)
        .sort((a, b) => a.latency - b.latency);

    // 3. Gossip: ask each alive node for MORE peers
    const gossipPromises = aliveNodes.slice(0, 3).map(async (node) => {
        try {
            const res = await fetch(`${node.url}/api/p2p/peers`, { signal: AbortSignal.timeout(3000) });
            if (res.ok) {
                const data = await res.json();
                const peers = data.peers || [];
                for (const p of peers) {
                    if (p.url && !seedUrls.has(p.url.replace(/\/+$/, ''))) {
                        seedUrls.add(p.url.replace(/\/+$/, ''));
                        // Ping the newly discovered peer
                        const result = await pingNode(p.url);
                        if (result.alive) aliveNodes.push(result);
                    }
                }
            }
        } catch (e) { }
    });
    await Promise.allSettled(gossipPromises);

    // 4. De-duplicate and sort by latency
    const seen = new Set();
    KNOWN_NODES = aliveNodes
        .filter(n => { if (seen.has(n.url)) return false; seen.add(n.url); return true; })
        .sort((a, b) => a.latency - b.latency);

    // 5. Pick best node
    if (KNOWN_NODES.length > 0) {
        PRIMARY_NODE = KNOWN_NODES[0];
        API_URL = PRIMARY_NODE.url + '/api';
        localStorage.setItem('tairuma_api_url', API_URL);
        // Save known nodes for next session
        localStorage.setItem('tairuma_known_nodes', JSON.stringify(KNOWN_NODES.map(n => n.url)));
    } else {
        PRIMARY_NODE = null;
    }

    console.log(`🌲 P2P Discovery: ${KNOWN_NODES.length} nodos vivos`, KNOWN_NODES);
    return KNOWN_NODES;
}

async function failoverToNextNode() {
    if (KNOWN_NODES.length <= 1) {
        // Re-scan all
        await discoverNodes();
        return;
    }
    // Remove dead primary
    KNOWN_NODES.shift();
    PRIMARY_NODE = KNOWN_NODES[0];
    API_URL = PRIMARY_NODE.url + '/api';
    localStorage.setItem('tairuma_api_url', API_URL);
    showToast(`Reconectado a nodo: ${PRIMARY_NODE.url}`, 'info');
    console.log(`🔄 Failover to: ${PRIMARY_NODE.url}`);
}

function updateNodeStatusUI() {
    const statusDot = document.getElementById('connection-status');
    const statusMsg = document.getElementById('auth-status-msg');
    const aliveCount = KNOWN_NODES.filter(n => n.alive).length;

    if (aliveCount > 0) {
        statusDot?.classList.remove('offline');
        statusDot?.classList.add('online');
        if (statusMsg && !CURRENT_ALIAS) {
            statusMsg.innerHTML = `✅ Conectado — ${aliveCount} nodo${aliveCount > 1 ? 's' : ''} en la red`;
        }
    } else {
        statusDot?.classList.remove('online');
        statusDot?.classList.add('offline');
        if (statusMsg) {
            statusMsg.innerHTML = `❌ Sin conexión al Bosque<br><small>Verifica tu internet o el nodo.</small>`;
        }
    }
}

// ============================================
// INITIALIZATION
// ============================================
document.addEventListener('DOMContentLoaded', async () => {
    try {
        setupConnectivityListeners();
        showBalanceSkeleton();

        const statusDisplay = document.getElementById('auth-status-msg');
        if (statusDisplay) statusDisplay.textContent = "📡 Buscando nodos en la red P2P...";

        // P2P Multi-Node Discovery
        await discoverNodes();
        updateNodeStatusUI();

        if (PRIMARY_NODE) {
            if (!CURRENT_ALIAS || !CURRENT_SEED) {
                document.getElementById('auth-overlay').style.display = 'flex';
            } else {
                document.getElementById('auth-overlay').style.display = 'none';
                loadDashboardData();
                _dashboardInterval = setInterval(loadDashboardData, 10000);
            }

            // Periodic re-discovery every 60s
            _discoveryInterval = setInterval(async () => {
                await discoverNodes();
                updateNodeStatusUI();
            }, 60000);
        } else {
            // No nodes found
            if (statusDisplay) {
                statusDisplay.innerHTML = `❌ Sin conexión al Bosque<br><small>No se encontraron nodos activos.</small>`;
            }
            document.getElementById('auth-overlay').style.display = 'flex';
        }

        setupEventListeners();
    } catch (e) {
        console.error("Critical Init Error:", e);
    }
});

// ============================================
// DASHBOARD DATA LOAD
// ============================================
async function loadDashboardData() {
    if (!CURRENT_ALIAS) return;

    try {
        // 1. User data
        const userRes = await apiFetch(`/numa/${CURRENT_ALIAS}`);
        const user = await userRes.json();
        const isFounder = user.alias === 'Numa_Fundador';

        MY_ZONE = user.zona || 'Bosque Profundo';

        safeText('numa-alias', user.alias);
        safeText('balance', user.saldo.toLocaleString('es-ES', { minimumFractionDigits: 2 }));
        if (document.getElementById('avail-balance'))
            document.getElementById('avail-balance').textContent = user.saldo.toFixed(2);
        safeText('user-rank', isFounder ? 'Fundador' : 'Semilla');

        // Daily phrase
        const SOULFUL_QUOTES = [
            "El bosque no tiene prisa, y aun así todo se cumple.",
            "Tu riqueza no es lo que guardas, es lo que compartes.",
            "Somos raíces de un mismo árbol inmenso.",
            "Escucha al viento, trae mensajes de antiguos tiempos.",
            "La verdadera moneda es la confianza entre hermanos.",
            "Si cuidas la tierra, ella te devolverá cien veces más.",
            "No eres una gota en el océano, eres el océano en una gota.",
            "Camina suave, la tierra siente tus pasos.",
            "Lo que das al ciclo, regresa a ti renovado.",
            "Tu energía es la semilla de la realidad que habitas."
        ];
        const daySeed = new Date().getDate() + (CURRENT_SEED ? CURRENT_SEED.charCodeAt(0) : 0);
        safeText('daily-phrase', `"${SOULFUL_QUOTES[daySeed % SOULFUL_QUOTES.length]}"`);
        safeText('user-invite-code', user.alias);

        // Zone
        safeText('user-zone', MY_ZONE);
        safeText('my-zone-display', MY_ZONE);
        safeText('my-current-zone-display', MY_ZONE);

        // 2. Dynamic value
        const svcdtRes = await apiFetch('/svcdt');
        const svcdt = await svcdtRes.json();
        safeText('svcdt-value', `${svcdt.valor}x`);

        // 3. Market
        const mercadoRes = await apiFetch('/mercado');
        const productos = await mercadoRes.json();
        renderMercado(productos);

        // 4. Governance
        try {
            const govRes = await apiFetch('/gobernanza');
            const propuestas = await govRes.json();
            renderGobernanza(propuestas);
        } catch (e) { console.log('Error loading governance', e); }

        // 5. Chat & Groups
        try {
            const chatUrl = `/chat/mensajes?alias=${CURRENT_ALIAS}&contexto=${CHAT_CONTEXT.type}&id_contexto=${CHAT_CONTEXT.id}`;
            const chatRes = await apiFetch(chatUrl);
            const mensajes = await chatRes.json();

            const gruposRes = await apiFetch('/grupos');
            const grupos = await gruposRes.json();
            renderChat(mensajes, grupos);
        } catch (e) { console.log('Error loading chat', e); }

        // 6. Nodes
        try {
            const nodesRes = await apiFetch('/red/nodos');
            const nodes = await nodesRes.json();
            renderNodos(nodes);
        } catch (e) { console.log('Error loading nodes', e); }

        // 7. Referrals
        try {
            const refRes = await apiFetch(`/referidos/${CURRENT_ALIAS}`);
            const referidos = await refRes.json();
            const refContainer = document.getElementById('my-referrals-list');
            if (refContainer) {
                if (referidos.length === 0) {
                    refContainer.innerHTML = '<p style="opacity:0.6; font-size:0.9rem;">Aún no has sembrado semillas.</p>';
                } else {
                    refContainer.innerHTML = referidos.map(r => `
                        <div class="setting-item referral-item">
                            <strong>${r.alias}</strong>
                            <span style="opacity:0.6;">Semilla brotada</span>
                        </div>
                    `).join('');
                }
            }
        } catch (e) { console.error("Error loading referrals", e); }

        // QR Code (local generation via QRCode.js)
        const qrContainer = document.getElementById('qr-image');
        const receiveAlias = document.getElementById('receive-alias');
        if (qrContainer && receiveAlias) {
            if (!qrContainer.dataset.alias || qrContainer.dataset.alias !== CURRENT_ALIAS) {
                qrContainer.innerHTML = '';
                if (typeof QRCode !== 'undefined') {
                    new QRCode(qrContainer, {
                        text: CURRENT_ALIAS,
                        width: 150,
                        height: 150,
                        colorDark: '#1a3c26',
                        colorLight: '#ffffff',
                        correctLevel: QRCode.CorrectLevel.M
                    });
                } else {
                    qrContainer.innerHTML = '<p style="opacity:0.5; font-size:0.85rem;">QR no disponible</p>';
                }
                qrContainer.dataset.alias = CURRENT_ALIAS;
            }
            receiveAlias.textContent = CURRENT_ALIAS;
        }

        // 8. Transaction history
        try {
            const txRes = await apiFetch(`/transacciones/${CURRENT_ALIAS}`);
            const txList = await txRes.json();
            renderTxHistory(txList);
        } catch (e) { console.log('No tx history endpoint or error', e); }

        // 9. P2P Network Stats
        updateP2PStats();

        // 10. Reputation
        try {
            const repRes = await apiFetch(`/reputacion/${CURRENT_ALIAS}`);
            const repData = await repRes.json();
            safeText('user-reputation', `${repData.semillas || repData.total || 0} semillas`);
        } catch (e) { }

    } catch (error) {
        console.error("Error cargando dashboard:", error);
    }
}

// ============================================
// RENDERING HELPERS
// ============================================
function safeText(id, text) {
    const el = document.getElementById(id);
    if (el) el.textContent = text;
}

function sanitizeHTML(str) {
    const div = document.createElement('div');
    div.textContent = str;
    return div.innerHTML;
}

function timeAgo(dateStr) {
    const now = new Date();
    const d = new Date(dateStr);
    const diff = Math.floor((now - d) / 1000);
    if (diff < 60) return 'Ahora';
    if (diff < 3600) return `${Math.floor(diff / 60)}m`;
    if (diff < 86400) return `${Math.floor(diff / 3600)}h`;
    return `${Math.floor(diff / 86400)}d`;
}

// ============================================
// MARKET FILTER
// ============================================
function setMarketFilter(filter) {
    MARKET_FILTER = filter;

    const btnGlobal = document.getElementById('filter-global');
    const btnLocal = document.getElementById('filter-local');

    if (filter === 'global') {
        btnGlobal.classList.add('active');
        btnGlobal.style.cssText = 'padding:5px 12px; border-radius:18px; border:none; background:white; font-size:0.8rem; box-shadow:0 2px 5px rgba(0,0,0,0.1); opacity:1;';
        btnLocal.classList.remove('active');
        btnLocal.style.cssText = 'padding:5px 12px; border-radius:18px; border:none; background:transparent; font-size:0.8rem; opacity:0.6;';
    } else {
        btnLocal.classList.add('active');
        btnLocal.style.cssText = 'padding:5px 12px; border-radius:18px; border:none; background:white; font-size:0.8rem; box-shadow:0 2px 5px rgba(0,0,0,0.1); opacity:1;';
        btnGlobal.classList.remove('active');
        btnGlobal.style.cssText = 'padding:5px 12px; border-radius:18px; border:none; background:transparent; font-size:0.8rem; opacity:0.6;';
    }

    loadDashboardData();
}

// ============================================
// RENDER: MERCADO
// ============================================
function renderMercado(productos) {
    const container = document.getElementById('bosque-mercado');
    if (!container) return;

    let displayProducts = productos;
    if (MARKET_FILTER === 'local') {
        displayProducts = productos.filter(p => p.zona === MY_ZONE);
    }

    const list = container.querySelector('.mercado-items');
    if (!list) return;

    if (displayProducts.length === 0) {
        list.innerHTML = '<p class="hint">El mercado está tranquilo por aquí. 🍃</p>';
        return;
    }

    list.innerHTML = displayProducts.map(p => {
        const icon = p.categoria === 'Servicio' ? '🛠️' : '📦';
        const isMe = p.alias === CURRENT_ALIAS;
        const hue = (p.producto.length * 25) % 360;
        const bgStyle = `background: linear-gradient(135deg, hsl(${hue}, 40%, 92%), hsl(${hue}, 40%, 82%)); color: hsl(${hue}, 60%, 30%);`;

        return `
        <div class="product-card premium">
            <div class="product-image-placeholder" style="${bgStyle}">
                <span style="font-size:2rem;">${icon}</span>
            </div>
            <div class="product-details">
                <div class="product-header">
                    <strong class="product-title">${p.producto}</strong>
                    <span class="badge small" style="background:rgba(0,0,0,0.05); color:var(--earth-deep);">${p.zona || 'Lejano'}</span>
                </div>
                <div class="product-meta">
                    <span class="seller-alias" onclick="contactarVendedor('${p.alias}', '${p.producto}')">@${p.alias}</span>
                    <span class="trust-score">🌱 ${p.semillas_confianza || 0}</span>
                </div>
                <p class="product-desc">${p.descripcion}</p>
                
                <div class="product-actions">
                    <span class="product-price">${p.precio} <small>Numas</small> <small style="opacity:0.5;">(${p.precio}\u20ac)</small></span>
                    <div style="display:flex; gap:5px;">
                        <button class="secondary-btn small" onclick="contactarVendedor('${p.alias}', '${p.producto}')">Tratar</button>
                        ${!isMe ? `<button class="icon-btn" onclick="sembrarConfianza('${p.alias}')" title="Sembrar Confianza">🌱</button>` : ''}
                    </div>
                </div>
            </div>
        </div>
    `}).join('');
}

// ============================================
// RENDER: GOVERNANCE
// ============================================
function renderGobernanza(propuestas) {
    const container = document.getElementById('proposals-list');
    if (!container) return;
    if (propuestas.length === 0) {
        container.innerHTML = '<p class="hint">Sin propuestas activas. Sé el primero en sembrar una idea. 🌱</p>';
        return;
    }
    container.innerHTML = propuestas.map(p => {
        const total = p.votos_pro + p.votos_con;
        const pctPro = total > 0 ? Math.round((p.votos_pro / total) * 100) : 0;
        const pctCon = total > 0 ? Math.round((p.votos_con / total) * 100) : 0;
        const isMine = p.autor === CURRENT_ALIAS;
        return `
        <div class="balance-card governance-card">
            ${isMine ? `
                <div style="position:absolute; top:10px; right:10px; display:flex; gap:5px;">
                    <button onclick="editProposal(${p.id}, '${p.titulo}', '${p.descripcion}')" style="border:none; background:none; cursor:pointer; font-size:1rem; opacity:0.6;" title="Editar">✏️</button>
                    <button onclick="deleteProposal(${p.id})" style="border:none; background:none; cursor:pointer; font-size:1rem; opacity:0.6;" title="Eliminar">🗑️</button>
                </div>
            ` : ''}
            <h4 style="margin-bottom:5px; padding-right:50px;">${p.titulo}</h4>
            <p style="font-size:0.85rem; margin-bottom:12px; opacity:0.8; line-height:1.4;">${p.descripcion}</p>
            <div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:5px; font-size:0.8rem;">
                <span style="color:var(--success);">A favor: ${pctPro}%</span>
                <span style="color:var(--error); opacity:0.8;">En contra: ${pctCon}%</span>
            </div>
            <div style="display:flex; gap:3px; margin-bottom:12px; height:6px; background:rgba(0,0,0,0.06); border-radius:4px; overflow:hidden;">
                <div style="width:${pctPro}%; background:var(--success); border-radius:4px; transition:width 0.5s ease;"></div>
                <div style="width:${pctCon}%; background:var(--error); opacity:0.7; border-radius:4px; transition:width 0.5s ease;"></div>
            </div>
            <div style="display:flex; gap:10px;">
                <button onclick="votarPropuesta(${p.id}, 'PRO')" class="secondary-btn small" style="flex:1;">👍 ${p.votos_pro}</button>
                <button onclick="votarPropuesta(${p.id}, 'CON')" class="secondary-btn small" style="flex:1;">👎 ${p.votos_con}</button>
            </div>
        </div>
    `}).join('');
}

// ============================================
// RENDER: CHAT
// ============================================
function renderChat(mensajes, grupos = []) {
    const chatHeader = document.getElementById('chat-header-title');
    if (chatHeader) chatHeader.textContent = CHAT_CONTEXT.name;

    // Avatar updates
    document.querySelectorAll('.numa-avatar').forEach(el => {
        if (!el.dataset.init) {
            el.innerHTML = `<span style="font-size:2rem;">${getNatureAvatar(CURRENT_ALIAS)}</span>`;
            el.style.backgroundImage = 'none';
            el.style.backgroundColor = '#e8f5e9';
            el.style.display = 'flex';
            el.style.alignItems = 'center';
            el.style.justifyContent = 'center';
            el.dataset.init = "true";
        }
    });

    // Groups bar
    const groupListEl = document.getElementById('group-list-container');
    if (groupListEl) {
        let activeBtn = '';
        if (CHAT_CONTEXT.type === 'grupo') {
            activeBtn = `<button class="tab-btn active" onclick="switchChat('grupo', ${CHAT_CONTEXT.id}, '${CHAT_CONTEXT.name}')">🌲 ${CHAT_CONTEXT.name}</button>`;
        }
        groupListEl.innerHTML = `
            <div style="font-size:0.75rem; opacity:0.5; margin-bottom:5px; text-transform:uppercase; letter-spacing:0.05em;">Círculos</div>
            <button class="tab-btn ${CHAT_CONTEXT.type === 'global' ? 'active' : ''}" onclick="switchChat('global', 'global', 'Bosque Global')">🌍 Global</button>
            ${activeBtn}
            <button class="secondary-btn small" onclick="openGroupExplorer()" style="margin-top:10px; margin-left: 5px;">🔍 Explorar</button>
        `;

        // Show edit controls for group creator
        if (CHAT_CONTEXT.type === 'grupo') {
            const currentGroup = grupos.find(g => g.id == CHAT_CONTEXT.id);
            if (currentGroup && currentGroup.creador_alias === CURRENT_ALIAS) {
                const headerTitle = document.getElementById('chat-header-title');
                if (headerTitle) {
                    headerTitle.innerHTML = `${CHAT_CONTEXT.name} 
                     <span onclick="editGroup(${CHAT_CONTEXT.id}, '${CHAT_CONTEXT.name}', '${currentGroup.descripcion || ''}')" style="cursor:pointer; font-size: 0.8em;">⚙️</span>
                     <span onclick="deleteGroup(${CHAT_CONTEXT.id})" style="cursor:pointer; font-size: 0.8em; margin-left:5px;">🗑️</span>`;
                }
            }
        }
    }

    // Messages
    const chatLog = document.getElementById('chat-container');
    if (chatLog) {
        const msgReverse = [...mensajes].reverse();
        chatLog.innerHTML = msgReverse.map(m => {
            const isMine = m.remitente === CURRENT_ALIAS;
            const avatar = getNatureAvatar(m.remitente);
            const time = new Date(m.fecha).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
            const escapedMsg = sanitizeHTML(m.mensaje);

            if (isMine) {
                return `
                <div class="chat-row mine">
                    <div class="chat-bubble mine">
                        <div class="msg-content">${escapedMsg}</div>
                        <div class="msg-meta">
                            ${time}
                            <button class="msg-action" onclick="editMessage(${m.id}, '${m.mensaje.replace(/'/g, "\\'").replace(/</g, '&lt;')}')">✏️</button>
                            <button class="msg-action" onclick="deleteMessage(${m.id}, this)">🗑️</button>
                        </div>
                    </div>
                </div>`;
            } else {
                return `
                <div class="chat-row other">
                    <div class="chat-avatar-container">
                        <span class="numa-avatar small">${avatar}</span>
                    </div>
                    <div class="chat-bubble other">
                        <div class="msg-sender">${sanitizeHTML(m.remitente)}</div>
                        <div class="msg-content">${sanitizeHTML(m.mensaje)}</div>
                        <div class="msg-meta">${time}</div>
                    </div>
                </div>`;
            }
        }).join('');
        // Smooth scroll to bottom
        chatLog.scrollTo({ top: chatLog.scrollHeight, behavior: 'smooth' });
    }
}

// ============================================
// RENDER: NODES
// ============================================
function renderNodos(nodos) {
    const container = document.getElementById('nodes-list');
    if (!container) return;

    // Use P2P KNOWN_NODES if available
    if (typeof KNOWN_NODES !== 'undefined' && KNOWN_NODES.length > 0) {
        container.innerHTML = KNOWN_NODES.map(n => {
            const statusClass = n.alive ? 'online' : 'offline';
            const statusText = n.alive ? `${n.latency}ms` : 'Sin respuesta';
            return `
            <div class="node-tree-card">
                <div class="node-icon-area" style="width:40px; height:40px;">
                    <span class="tree-icon small">${n.alive ? '🌳' : '🥀'}</span>
                </div>
                <div class="node-info" style="flex:1;">
                    <strong class="node-title">${n.alias || 'Nodo Tairuma'}</strong>
                    <div class="node-stats" style="font-size:0.75rem; opacity:0.6;">
                        ${n.url.replace(/https?:\/\//, '').substring(0, 35)}
                    </div>
                </div>
                <div style="text-align:right;">
                    <div class="status-indicator ${statusClass}"></div>
                    <small style="color:var(--${n.alive ? 'success' : 'error'}); font-size:0.7rem;">${statusText}</small>
                </div>
            </div>
        `}).join('');
    } else if (nodos && nodos.length > 0) {
        container.innerHTML = nodos.map(n => `
            <div class="node-tree-card">
                <div class="node-icon-area"><span class="tree-icon small">🌱</span></div>
                <div class="node-info">
                    <strong class="node-title">${n.alias || 'Nodo'}</strong>
                    <div class="node-stats"><span>${n.ip || 'Red Tairuma'}</span></div>
                </div>
                <div class="status-indicator online"></div>
            </div>
        `).join('');
    } else {
        container.innerHTML = '<p class="hint" style="text-align:center; opacity:0.5;">Solo tú en la red por ahora.</p>';
    }
}

function renderTxHistory(txList) {
    const container = document.getElementById('tx-history');
    if (!container) return;
    if (!txList || txList.length === 0) {
        container.innerHTML = '<p class="hint" style="opacity:0.5;">Sin movimientos aún.</p>';
        return;
    }
    // Show last 5 transactions
    const recent = txList.slice(-5).reverse();
    container.innerHTML = recent.map(tx => {
        const isPositive = tx.cantidad > 0;
        const color = isPositive ? 'var(--success)' : 'var(--error)';
        const sign = isPositive ? '+' : '';
        const icon = isPositive ? '📥' : '📤';
        return `
        <div class="setting-item" style="display:flex; justify-content:space-between; align-items:center; padding:10px 15px;">
            <div style="display:flex; align-items:center; gap:10px;">
                <span style="font-size:1.2rem;">${icon}</span>
                <div>
                    <div style="font-size:0.85rem; font-weight:500;">${sanitizeHTML(tx.descripcion || 'Movimiento')}</div>
                    <small style="opacity:0.5;">${timeAgo(tx.fecha)}</small>
                </div>
            </div>
            <strong style="color:${color}; font-size:0.95rem;">${sign}${tx.cantidad.toFixed(2)} N</strong>
        </div>
    `}).join('');
}

function updateP2PStats() {
    if (typeof KNOWN_NODES === 'undefined') return;
    const aliveCount = KNOWN_NODES.filter(n => n.alive).length;
    safeText('p2p-active-count', String(aliveCount));
    if (PRIMARY_NODE) {
        safeText('p2p-latency', String(PRIMARY_NODE.latency || '--'));
        safeText('p2p-version', PRIMARY_NODE.version || '--');
        const myUrl = PRIMARY_NODE.url.replace(/https?:\/\//, '').substring(0, 40);
        safeText('p2p-my-url', myUrl);
    }
    const badge = document.getElementById('p2p-status-badge');
    if (badge) {
        badge.textContent = aliveCount > 0 ? 'Activa' : 'Buscando...';
        badge.style.background = aliveCount > 0 ? 'var(--success)' : 'var(--warning)';
    }
}

// ============================================
// AUTH FUNCTIONS
// ============================================
function showRegister() {
    document.getElementById('login-form').style.display = 'none';
    document.getElementById('register-form').style.display = 'block';

    const urlParams = new URLSearchParams(window.location.search);
    const refAlias = urlParams.get('ref');
    if (refAlias) {
        const seedInput = document.getElementById('reg-code');
        if (seedInput) {
            seedInput.value = refAlias;
            seedInput.style.backgroundColor = '#f0fdf4';
            seedInput.style.borderColor = 'var(--forest-mid)';
        }
    }
}

function showLogin() {
    document.getElementById('register-form').style.display = 'none';
    document.getElementById('login-form').style.display = 'block';
}

async function authLogin() {
    const seed = document.getElementById('seed-input').value.trim();
    if (!seed) return showToast("Ingresa tu semilla para entrar", "warning");
    try {
        const res = await apiFetch('/auth/login', {
            method: 'POST', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ semilla: seed })
        });
        const data = await res.json();
        if (data.success) {
            localStorage.setItem('tairuma_alias', data.alias);
            localStorage.setItem('tairuma_seed', seed);
            if (data.token) localStorage.setItem('tairuma_token', data.token);
            CURRENT_ALIAS = data.alias;
            CURRENT_SEED = seed;
            showToast("¡Bienvenido al Bosque!", "success");
            setTimeout(() => location.reload(), 500);
        } else { showToast(data.detail || "Error al entrar", "error"); }
    } catch (e) { showToast("Error de conexión: " + e.message, "error"); }
}

async function authRegister() {
    const code = document.getElementById('reg-code').value.trim();
    const alias = document.getElementById('reg-alias').value.trim();
    const zona = document.getElementById('reg-zone').value.trim() || 'Bosque Profundo';
    if (!code || !alias) return showToast("Completa el código y tu alias", "warning");
    try {
        const res = await apiFetch('/auth/register', {
            method: 'POST', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ codigo_invitacion: code, alias_deseado: alias, zona: zona })
        });
        const data = await res.json();
        if (data.success) {
            document.getElementById('register-form').style.display = 'none';
            document.getElementById('seed-reveal').style.display = 'block';
            document.getElementById('new-seed-display').textContent = data.semilla;
            localStorage.setItem('temp_alias', data.alias);
            localStorage.setItem('temp_seed', data.semilla);
            if (data.token) localStorage.setItem('temp_token', data.token);
            showToast("¡Tu semilla ha germinado!", "success");
        } else { showToast(data.detail || "Error en registro", "error"); }
    } catch (e) { showToast("Error: " + e.message, "error"); }
}

function copySeed() {
    const seed = document.getElementById('new-seed-display').textContent;
    navigator.clipboard.writeText(seed).then(() => showToast("Semilla copiada al portapapeles", "success"));
}

function finishAuth() {
    localStorage.setItem('tairuma_alias', localStorage.getItem('temp_alias'));
    localStorage.setItem('tairuma_seed', localStorage.getItem('temp_seed'));
    const tempToken = localStorage.getItem('temp_token');
    if (tempToken) localStorage.setItem('tairuma_token', tempToken);
    localStorage.removeItem('temp_token');
    location.reload();
}

// ============================================
// NAVIGATION — SMOOTH VIEW TRANSITIONS
// ============================================
window.switchView = function (viewName) {
    const currentView = document.querySelector('.app-view.active');
    const target = document.getElementById(`view-${viewName}`);
    if (!target || target === currentView) return;

    // Fade out current
    if (currentView) {
        currentView.style.opacity = '0';
        currentView.style.transform = 'translateY(8px)';
        setTimeout(() => {
            currentView.classList.remove('active');
            currentView.style.display = 'none';
            currentView.style.opacity = '';
            currentView.style.transform = '';

            // Show new
            target.style.display = 'block';
            target.classList.add('active');
        }, 150);
    } else {
        target.classList.add('active');
        target.style.display = 'block';
    }

    // Update nav
    document.querySelectorAll('.nav-item').forEach(el => el.classList.remove('active'));
    const btn = Array.from(document.querySelectorAll('.nav-item')).find(b => b.getAttribute('onclick')?.includes(viewName));
    if (btn) btn.classList.add('active');

    // Scroll content to top
    const content = document.querySelector('.app-content');
    if (content) content.scrollTo({ top: 0, behavior: 'smooth' });
};

// ============================================
// BOSQUE TABS
// ============================================
window.filterBosque = function (tab) {
    document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
    document.querySelectorAll('.bosque-section').forEach(el => {
        el.style.display = 'none';
        el.classList.remove('active');
    });
    if (tab === 'chat') {
        document.getElementById('btn-chat')?.classList.add('active');
        const chatEl = document.getElementById('bosque-chat');
        if (chatEl) { chatEl.style.display = 'flex'; chatEl.classList.add('active'); }
    } else if (tab === 'mercado') {
        document.getElementById('btn-mercado')?.classList.add('active');
        document.getElementById('bosque-mercado').style.display = 'block';
    } else if (tab === 'propuestas') {
        document.getElementById('btn-propuestas')?.classList.add('active');
        document.getElementById('bosque-propuestas').style.display = 'block';
    } else if (tab === 'nodos') {
        document.getElementById('btn-nodos')?.classList.add('active');
        document.getElementById('bosque-nodos').style.display = 'block';
    }
};

// ============================================
// INTERACTIONS
// ============================================
window.contactarVendedor = function (alias, item) {
    if (alias === CURRENT_ALIAS) return showToast("¡Es tu propia oferta!", "info");
    // Switch to private chat with seller
    switchChat('global', 'global', 'Bosque Global');
    switchView('bosque');
    filterBosque('chat');
    setTimeout(() => {
        const chatInput = document.getElementById('chat-msg');
        if (chatInput) {
            chatInput.value = `@${alias} Hola, me interesa "${item}" 🤝`;
            chatInput.focus();
        }
    }, 300);
};

window.sembrarConfianza = async function (alias) {
    try {
        const res = await apiFetch('/reputacion/votar', {
            method: 'POST', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ votante_alias: CURRENT_ALIAS, objetivo_alias: alias })
        });
        const data = await res.json();
        showToast(`🌱 ${data.mensaje}`, "success");
        loadDashboardData();
    } catch (e) { showToast("Error al sembrar confianza", "error"); }
};

window.editZone = async function () {
    const newZone = prompt("Ingresa tu Barrio o Vereda:", MY_ZONE);
    if (newZone && newZone !== MY_ZONE) {
        try {
            await apiFetch('/perfil/zona', {
                method: 'PUT', headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ alias: CURRENT_ALIAS, zona: newZone })
            });
            showToast("Zona actualizada", "success");
            loadDashboardData();
        } catch (e) { showToast("Error actualizando zona", "error"); }
    }
};

window.logoutUser = function () {
    localStorage.removeItem('tairuma_alias');
    localStorage.removeItem('tairuma_seed');
    localStorage.removeItem('tairuma_token');
    showToast("¡Hasta pronto! 🌲", "info");
    setTimeout(() => location.reload(), 500);
};

// ============================================
// MARKET ITEMS
// ============================================
window.submitNewItem = async function () {
    const cat = document.getElementById('item-category').value;
    const name = document.getElementById('item-name').value;
    const price = parseFloat(document.getElementById('item-price').value);
    const desc = document.getElementById('item-desc').value;
    const zone = document.getElementById('item-zone').value || MY_ZONE;

    if (!name || isNaN(price)) {
        return showToast("Completa el nombre y precio", "warning");
    }

    try {
        await apiFetch('/mercado', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                alias: CURRENT_ALIAS, producto: name, precio: price,
                categoria: cat, descripcion: desc, zona: zone
            })
        });
        document.getElementById('new-item-modal').style.display = 'none';
        document.getElementById('item-name').value = '';
        document.getElementById('item-price').value = '';
        document.getElementById('item-desc').value = '';
        showToast("Oferta publicada en el mercado 🤝", "success");
        loadDashboardData();
    } catch (e) {
        showToast("Error publicando oferta", "error");
    }
};

// ============================================
// GOVERNANCE
// ============================================
window.editProposal = async function (id, tit, desc) {
    const newTit = prompt("Editar Título:", tit);
    if (!newTit) return;
    const newDesc = prompt("Editar Propósito:", desc);
    if (!newDesc) return;
    try {
        await apiFetch(`/gobernanza/propuesta/${id}`, {
            method: 'PUT', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ autor: CURRENT_ALIAS, nuevo_titulo: newTit, nueva_descripcion: newDesc })
        });
        showToast("Propuesta actualizada", "success");
        loadDashboardData();
    } catch (e) { showToast("Error editando propuesta", "error"); }
};

window.deleteProposal = async function (id) {
    if (!confirm("¿Retirar esta propuesta del consejo?")) return;
    try {
        await apiFetch(`/gobernanza/propuesta/${id}?autor=${CURRENT_ALIAS}`, { method: 'DELETE' });
        showToast("Propuesta retirada", "info");
        loadDashboardData();
    } catch (e) { showToast("Error al borrar propuesta", "error"); }
};

async function votarPropuesta(id, opcion) {
    try {
        const res = await apiFetch('/gobernanza/votar', {
            method: 'POST', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ propuesta_id: id, usuario_alias: CURRENT_ALIAS, opcion: opcion })
        });
        const data = await res.json();
        if (data.status === 'success') {
            showToast(opcion === 'PRO' ? '👍 Voto registrado a favor' : '👎 Voto registrado en contra', 'success');
            loadDashboardData();
        } else showToast(data.detail, 'warning');
    } catch (e) { showToast("Error al votar", "error"); }
}

// ============================================
// CHAT MESSAGES
// ============================================
window.deleteMessage = function (id) {
    document.getElementById('delete-msg-id').value = id;
    document.getElementById('delete-msg-modal').style.display = 'flex';
};

window.submitDeleteMessage = async function () {
    const id = document.getElementById('delete-msg-id').value;
    try {
        await apiFetch(`/chat/${id}?remitente=${CURRENT_ALIAS}`, { method: 'DELETE' });
        showToast("Mensaje borrado", "info");
        loadDashboardData();
        document.getElementById('delete-msg-modal').style.display = 'none';
    } catch (e) { showToast("No se pudo borrar el mensaje", "error"); }
};

window.editMessage = function (id, oldText) {
    document.getElementById('edit-msg-id').value = id;
    document.getElementById('edit-msg-text').value = oldText;
    document.getElementById('edit-msg-modal').style.display = 'flex';
};

window.submitEditMessage = async function () {
    const id = document.getElementById('edit-msg-id').value;
    const newText = document.getElementById('edit-msg-text').value.trim();
    if (newText) {
        try {
            await apiFetch(`/chat/${id}`, {
                method: 'PUT', headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ remitente: CURRENT_ALIAS, nuevo_mensaje: newText })
            });
            document.getElementById('edit-msg-modal').style.display = 'none';
            showToast("Mensaje editado", "success");
            loadDashboardData();
        } catch (e) { showToast("Error al editar", "error"); }
    }
};

// ============================================
// GROUPS
// ============================================
window.openGroupExplorer = async function () {
    document.getElementById('group-explorer-modal').style.display = 'flex';
    document.getElementById('all-groups-list').innerHTML = '<div class="skeleton skeleton-card"></div><div class="skeleton skeleton-card"></div>';
    try {
        const res = await apiFetch('/grupos');
        ALL_GROUPS_CACHE = await res.json();
        renderGroupExplorerList(ALL_GROUPS_CACHE);
    } catch (e) { showToast("Error cargando círculos", "error"); }
};

window.closeGroupExplorer = function () { document.getElementById('group-explorer-modal').style.display = 'none'; };

window.filterGroups = function (query) {
    if (!query) return renderGroupExplorerList(ALL_GROUPS_CACHE);
    const lower = query.toLowerCase();
    const filtered = ALL_GROUPS_CACHE.filter(g => g.nombre.toLowerCase().includes(lower) || g.descripcion.toLowerCase().includes(lower));
    renderGroupExplorerList(filtered);
};

function renderGroupExplorerList(lista) {
    const container = document.getElementById('all-groups-list');
    if (lista.length === 0) { container.innerHTML = '<p class="hint">No se encontraron círculos.</p>'; return; }
    container.innerHTML = lista.map(g => {
        const isMine = g.creador_alias === CURRENT_ALIAS;
        return `
        <div class="setting-item" style="cursor:pointer;" onclick="switchChat('grupo', ${g.id}, '${g.nombre}'); closeGroupExplorer();">
            <div style="display:flex; align-items:center; gap:10px; width:100%;">
                <span style="font-size:1.5rem;">🌲</span>
                <div style="flex:1;">
                    <strong style="display:block;">${g.nombre}</strong>
                    <small style="opacity:0.6;">${g.descripcion || 'Sin descripción'}</small>
                </div>
                ${isMine ? '<span style="font-size:0.75rem; background:var(--forest-mid); color:white; padding:2px 8px; border-radius:6px;">Tuyo</span>' : ''}
            </div>
        </div>
    `}).join('');
}

window.editGroup = function (id, name, desc) {
    document.getElementById('edit-group-id').value = id;
    document.getElementById('edit-group-name').value = name;
    document.getElementById('edit-group-desc').value = desc;
    document.getElementById('edit-group-modal').style.display = 'flex';
};

window.submitEditGroup = async function () {
    const id = document.getElementById('edit-group-id').value;
    const name = document.getElementById('edit-group-name').value;
    const desc = document.getElementById('edit-group-desc').value;
    try {
        await apiFetch(`/grupos/${id}`, {
            method: 'PUT', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ creador_alias: CURRENT_ALIAS, nuevo_nombre: name, nueva_descripcion: desc })
        });
        document.getElementById('edit-group-modal').style.display = 'none';
        showToast("Círculo actualizado", "success");
        loadDashboardData();
    } catch (e) { showToast("Error editando círculo", "error"); }
};

window.deleteGroup = async function () {
    const id = document.getElementById('edit-group-id').value;
    if (!confirm("¿PODAR (Eliminar) este círculo para siempre?")) return;
    try {
        await apiFetch(`/grupos/${id}?creador_alias=${CURRENT_ALIAS}`, { method: 'DELETE' });
        document.getElementById('edit-group-modal').style.display = 'none';
        showToast("Círculo podado", "info");
        switchChat('global', 'global', 'Bosque Global');
    } catch (e) { showToast("Error eliminando círculo", "error"); }
};

function switchChat(type, id, name) {
    CHAT_CONTEXT = { type, id, name };
    loadDashboardData();
}

// ============================================
// SEND CHAT
// ============================================
async function sendChat() {
    const chatInput = document.getElementById('chat-msg');
    const sendBtn = document.querySelector('.send-btn');
    const msgText = chatInput.value.trim();
    if (msgText) {
        if (chatInput.disabled) return;
        chatInput.disabled = true;
        sendBtn.disabled = true;
        const payload = { remitente: CURRENT_ALIAS, mensaje: msgText };
        if (CHAT_CONTEXT.type === 'grupo') payload.grupo_id = CHAT_CONTEXT.id;
        else if (CHAT_CONTEXT.type === 'privado') payload.destinatario = CHAT_CONTEXT.id;
        else payload.destinatario = 'Global';
        try {
            await apiFetch('/chat', {
                method: 'POST', headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(payload)
            });
            chatInput.value = '';
            loadDashboardData();
        } catch (e) { showToast("Error enviando mensaje", "error"); }
        finally {
            chatInput.disabled = false;
            sendBtn.disabled = false;
            chatInput.focus();
        }
    }
}

// ============================================
// PROPOSALS
// ============================================
window.submitProposal = async function () {
    const titulo = document.getElementById('prop-title').value.trim();
    const desc = document.getElementById('prop-desc').value.trim();
    const btn = document.querySelector('#new-proposal-modal .primary-btn');
    if (!titulo || !desc) return showToast("Completa título y descripción", "warning");
    btn.disabled = true;
    try {
        await apiFetch('/gobernanza/propuesta', {
            method: 'POST', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ autor: CURRENT_ALIAS, titulo: titulo, descripcion: desc })
        });
        document.getElementById('new-proposal-modal').style.display = 'none';
        document.getElementById('prop-title').value = '';
        document.getElementById('prop-desc').value = '';
        showToast("Propuesta plantada con éxito 🌱", "success");
        loadDashboardData();
    } catch (e) { showToast("Error al sembrar propuesta: " + e.message, "error"); }
    finally { btn.disabled = false; }
};

// ============================================
// EVENT LISTENERS
// ============================================
function setupEventListeners() {
    // Transfer
    document.getElementById('transfer-btn')?.addEventListener('click', async () => {
        const dest = document.getElementById('dest-alias').value.trim();
        const amount = parseFloat(document.getElementById('transfer-amount').value);
        if (!dest || !amount || amount <= 0) return showToast("Completa destinatario y cantidad", "warning");
        try {
            const res = await apiFetch('/transferir', {
                method: 'POST', headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ remitente_alias: CURRENT_ALIAS, destinatario_alias: dest, cantidad: amount })
            });
            const data = await res.json();
            if (data.status === 'success') {
                showToast(`✅ ${amount} Numas enviados a ${dest}`, 'success');
                document.getElementById('dest-alias').value = '';
                document.getElementById('transfer-amount').value = '';
                switchView('home'); loadDashboardData();
            } else showToast(data.detail || 'Error en envío', 'error');
        } catch (err) { showToast("Error de conexión", "error"); }
    });

    // Chat
    const chatInput = document.getElementById('chat-msg');
    const sendBtn = document.querySelector('.send-btn');
    async function sendChatWrapper() { await sendChat(); }
    sendBtn?.addEventListener('click', sendChatWrapper);
    chatInput?.addEventListener('keypress', (e) => { if (e.key === 'Enter') sendChatWrapper(); });

    window.copyStaticInviteCode = function () {
        const code = document.getElementById('user-invite-code').textContent;
        if (code && code !== 'CARGANDO...') {
            navigator.clipboard.writeText(code).then(() => showToast("¡Código copiado!", "success"));
        }
    };

    // Group creation
    window.crearNuevoGrupo = function () {
        document.getElementById('new-group-modal').style.display = 'flex';
    };
    window.closeGroupModal = function () {
        document.getElementById('new-group-modal').style.display = 'none';
    };
    window.submitNewGroup = async function () {
        const nombre = document.getElementById('new-group-name').value.trim();
        const desc = document.getElementById('new-group-desc').value.trim();
        if (!nombre) return showToast("Nombre del círculo requerido", "warning");
        try {
            await apiFetch('/grupos', {
                method: 'POST', headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ nombre, descripcion: desc, creador_alias: CURRENT_ALIAS, tipo: 'Publico' })
            });
            closeGroupModal();
            showToast("Nuevo círculo sembrado 🌲", "success");
            loadDashboardData();
        } catch (e) { showToast("Error creando círculo", "error"); }
    };
}

// Misc
window.proposalModalBtn = function () { };
