"""
CASCADE Lattice Gateway - The Neural Internetwork Visualized

A proper landing page for CASCADE that shows:
1. The lattice structure - chains linked through cryptographic provenance
2. Interplanetary addresses (CIDs) with live resolution
3. Agent lineage visualization
4. Drill-down into any chain or record

"I think, therefore I hash."
"""

import json
from pathlib import Path
from typing import Dict, Any, List, Optional
from datetime import datetime

# Try to import IPLD tools
try:
    import dag_cbor
    HAS_DAG_CBOR = True
except ImportError:
    HAS_DAG_CBOR = False


def get_lattice_html() -> str:
    """
    Generate the full lattice gateway HTML with interactive visualization.
    """
    return """
<!DOCTYPE html>
<html>
<head>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        
        body {
            background: #000;
            color: #fff;
            font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
            overflow: hidden;
        }
        
        .gateway-container {
            width: 100%;
            height: 100vh;
            display: flex;
            flex-direction: column;
        }
        
        /* Hero Section */
        .hero {
            background: linear-gradient(180deg, #0a0a1a 0%, #000 100%);
            padding: 40px;
            text-align: center;
            border-bottom: 1px solid #1a1a2a;
            position: relative;
            overflow: hidden;
        }
        
        .hero::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: 
                radial-gradient(circle at 20% 50%, rgba(0, 255, 136, 0.05) 0%, transparent 50%),
                radial-gradient(circle at 80% 50%, rgba(0, 170, 255, 0.05) 0%, transparent 50%);
            pointer-events: none;
        }
        
        .hero h1 {
            font-size: 2.5em;
            font-weight: 300;
            letter-spacing: 0.1em;
            margin-bottom: 8px;
            background: linear-gradient(90deg, #0ff, #0f8, #0ff);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            animation: shimmer 3s ease-in-out infinite;
        }
        
        @keyframes shimmer {
            0%, 100% { filter: brightness(1); }
            50% { filter: brightness(1.3); }
        }
        
        .hero .subtitle {
            color: #666;
            font-size: 0.9em;
            letter-spacing: 0.2em;
            text-transform: uppercase;
        }
        
        .hero .genesis-badge {
            display: inline-block;
            margin-top: 20px;
            padding: 8px 20px;
            background: rgba(0, 255, 136, 0.1);
            border: 1px solid #0f8;
            border-radius: 20px;
            font-size: 0.75em;
            color: #0f8;
        }
        
        .hero .genesis-badge code {
            color: #0ff;
            margin-left: 8px;
        }
        
        /* Main Content */
        .main-content {
            flex: 1;
            display: flex;
            overflow: hidden;
        }
        
        /* Lattice Graph Panel */
        .lattice-panel {
            flex: 2;
            padding: 20px;
            overflow: auto;
            position: relative;
        }
        
        .lattice-canvas {
            width: 100%;
            height: 100%;
            min-height: 400px;
            position: relative;
        }
        
        /* Chain Node Styling */
        .chain-node {
            position: absolute;
            background: #111;
            border: 2px solid #333;
            border-radius: 12px;
            padding: 16px;
            min-width: 280px;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
        }
        
        .chain-node:hover {
            border-color: #0ff;
            transform: translateY(-2px);
            box-shadow: 0 8px 30px rgba(0, 255, 255, 0.2);
        }
        
        .chain-node.genesis {
            border-color: #0f8;
            background: linear-gradient(135deg, #0a1a0a 0%, #111 100%);
        }
        
        .chain-node.genesis::before {
            content: '◆';
            position: absolute;
            top: -12px;
            left: 50%;
            transform: translateX(-50%);
            background: #000;
            padding: 0 8px;
            color: #0f8;
            font-size: 1.2em;
        }
        
        .chain-node.selected {
            border-color: #f0f;
            box-shadow: 0 0 30px rgba(255, 0, 255, 0.3);
        }
        
        .chain-node .node-header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 12px;
        }
        
        .chain-node .node-name {
            font-weight: 600;
            font-size: 1.1em;
            color: #fff;
        }
        
        .chain-node .node-type {
            font-size: 0.7em;
            padding: 2px 8px;
            border-radius: 10px;
            background: #222;
            color: #888;
        }
        
        .chain-node.genesis .node-type {
            background: rgba(0, 255, 136, 0.2);
            color: #0f8;
        }
        
        .chain-node .merkle-root {
            font-family: monospace;
            font-size: 0.85em;
            color: #0ff;
            background: #0a0a1a;
            padding: 6px 10px;
            border-radius: 6px;
            margin-bottom: 10px;
            word-break: break-all;
        }
        
        .chain-node .cid {
            font-size: 0.7em;
            color: #666;
            margin-top: 8px;
            word-break: break-all;
        }
        
        .chain-node .cid a {
            color: #08f;
            text-decoration: none;
        }
        
        .chain-node .cid a:hover {
            text-decoration: underline;
        }
        
        .chain-node .node-stats {
            display: flex;
            gap: 12px;
            margin-top: 10px;
            font-size: 0.75em;
            color: #666;
        }
        
        .chain-node .node-stats span {
            display: flex;
            align-items: center;
            gap: 4px;
        }
        
        /* Connection Lines */
        .connection-line {
            position: absolute;
            pointer-events: none;
            z-index: -1;
        }
        
        .connection-line svg {
            overflow: visible;
        }
        
        .connection-line path {
            fill: none;
            stroke: #333;
            stroke-width: 2;
            stroke-dasharray: 8, 4;
            animation: flowDash 1s linear infinite;
        }
        
        @keyframes flowDash {
            to { stroke-dashoffset: -12; }
        }
        
        /* Detail Panel */
        .detail-panel {
            flex: 1;
            background: #0a0a0a;
            border-left: 1px solid #1a1a2a;
            padding: 20px;
            overflow-y: auto;
            min-width: 350px;
        }
        
        .detail-panel h3 {
            color: #0ff;
            font-size: 0.9em;
            letter-spacing: 0.1em;
            text-transform: uppercase;
            margin-bottom: 16px;
            padding-bottom: 8px;
            border-bottom: 1px solid #222;
        }
        
        .detail-section {
            margin-bottom: 24px;
        }
        
        .detail-label {
            font-size: 0.7em;
            color: #666;
            text-transform: uppercase;
            letter-spacing: 0.1em;
            margin-bottom: 4px;
        }
        
        .detail-value {
            font-size: 0.9em;
            color: #fff;
            background: #111;
            padding: 10px;
            border-radius: 6px;
            word-break: break-all;
        }
        
        .detail-value.mono {
            font-family: monospace;
            color: #0ff;
        }
        
        .detail-value.link {
            color: #08f;
            cursor: pointer;
        }
        
        .detail-value.link:hover {
            text-decoration: underline;
        }
        
        /* Records List */
        .records-list {
            max-height: 300px;
            overflow-y: auto;
        }
        
        .record-item {
            background: #111;
            border: 1px solid #222;
            border-radius: 6px;
            padding: 10px;
            margin-bottom: 8px;
            cursor: pointer;
            transition: all 0.2s;
        }
        
        .record-item:hover {
            border-color: #0ff;
            background: #1a1a1a;
        }
        
        .record-item .record-name {
            font-weight: 500;
            color: #fff;
            margin-bottom: 4px;
        }
        
        .record-item .record-hash {
            font-size: 0.75em;
            color: #0ff;
            font-family: monospace;
        }
        
        /* Status Bar */
        .status-bar {
            background: #0a0a0a;
            border-top: 1px solid #1a1a2a;
            padding: 12px 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            font-size: 0.8em;
        }
        
        .status-bar .status-item {
            display: flex;
            align-items: center;
            gap: 8px;
            color: #666;
        }
        
        .status-bar .status-dot {
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background: #0f8;
            animation: pulse 2s ease-in-out infinite;
        }
        
        @keyframes pulse {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.5; }
        }
        
        .status-bar .ipfs-badge {
            background: linear-gradient(90deg, #04a, #06c);
            padding: 4px 12px;
            border-radius: 12px;
            color: #fff;
            font-weight: 500;
        }
        
        /* Empty State */
        .empty-state {
            text-align: center;
            padding: 60px 40px;
            color: #444;
        }
        
        .empty-state .icon {
            font-size: 3em;
            margin-bottom: 16px;
        }
        
        /* Resolve Input */
        .resolve-bar {
            background: #111;
            border-radius: 8px;
            padding: 12px;
            margin-bottom: 20px;
            display: flex;
            gap: 10px;
        }
        
        .resolve-bar input {
            flex: 1;
            background: #0a0a0a;
            border: 1px solid #333;
            border-radius: 6px;
            padding: 10px 14px;
            color: #fff;
            font-family: monospace;
            font-size: 0.85em;
        }
        
        .resolve-bar input:focus {
            outline: none;
            border-color: #0ff;
        }
        
        .resolve-bar button {
            background: linear-gradient(135deg, #0ff, #08f);
            border: none;
            border-radius: 6px;
            padding: 10px 20px;
            color: #000;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s;
        }
        
        .resolve-bar button:hover {
            transform: scale(1.02);
            box-shadow: 0 4px 20px rgba(0, 255, 255, 0.3);
        }
        
        /* Lineage Trail */
        .lineage-trail {
            display: flex;
            align-items: center;
            gap: 8px;
            padding: 10px;
            background: #0a0a0a;
            border-radius: 8px;
            overflow-x: auto;
            margin-bottom: 16px;
        }
        
        .lineage-step {
            display: flex;
            align-items: center;
            gap: 8px;
            white-space: nowrap;
        }
        
        .lineage-step .step-name {
            background: #1a1a2a;
            padding: 4px 12px;
            border-radius: 12px;
            font-size: 0.8em;
            cursor: pointer;
            transition: all 0.2s;
        }
        
        .lineage-step .step-name:hover {
            background: #2a2a3a;
        }
        
        .lineage-step .step-name.genesis {
            background: rgba(0, 255, 136, 0.2);
            color: #0f8;
        }
        
        .lineage-step .arrow {
            color: #333;
        }
    </style>
</head>
<body>
    <div class="gateway-container" id="gateway">
        <!-- Hero -->
        <div class="hero">
            <h1>CASCADE LATTICE</h1>
            <div class="subtitle">The Neural Internetwork</div>
            <div class="genesis-badge">
                GENESIS <code id="genesis-root">loading...</code>
            </div>
        </div>
        
        <!-- Main Content -->
        <div class="main-content">
            <!-- Lattice Visualization -->
            <div class="lattice-panel">
                <div class="resolve-bar">
                    <input type="text" id="cid-input" placeholder="Enter CID to resolve (bafyrei...)">
                    <button onclick="resolveCID()">Resolve</button>
                </div>
                
                <div class="lattice-canvas" id="lattice-canvas">
                    <!-- Nodes will be dynamically placed here -->
                </div>
            </div>
            
            <!-- Detail Panel -->
            <div class="detail-panel">
                <h3>Chain Details</h3>
                
                <div id="chain-details">
                    <div class="empty-state">
                        <div class="icon">◇</div>
                        <div>Select a chain to view details</div>
                    </div>
                </div>
            </div>
        </div>
        
        <!-- Status Bar -->
        <div class="status-bar">
            <div class="status-item">
                <div class="status-dot"></div>
                <span id="chain-count">0 chains indexed</span>
            </div>
            <div class="status-item">
                <span class="ipfs-badge">IPFS</span>
                <span id="ipfs-status">Ready</span>
            </div>
        </div>
    </div>
    
    <script>
        // Lattice data - will be populated by Python
        let latticeData = LATTICE_DATA_PLACEHOLDER;
        let selectedChain = null;
        
        function initLattice() {
            const canvas = document.getElementById('lattice-canvas');
            const chains = latticeData.chains || [];
            
            // Update status
            document.getElementById('chain-count').textContent = `${chains.length} chains indexed`;
            
            if (chains.length === 0) {
                canvas.innerHTML = `
                    <div class="empty-state">
                        <div class="icon">◇</div>
                        <div>No chains in lattice yet</div>
                        <div style="margin-top: 8px; font-size: 0.8em;">Birth an agent to begin</div>
                    </div>
                `;
                return;
            }
            
            // Set genesis root in hero
            const genesis = chains.find(c => c.name === 'genesis');
            if (genesis) {
                document.getElementById('genesis-root').textContent = genesis.merkle_root;
            }
            
            // Position chains in a hierarchical layout
            canvas.innerHTML = '';
            const nodePositions = {};
            
            chains.forEach((chain, idx) => {
                const isGenesis = chain.name === 'genesis';
                const level = isGenesis ? 0 : 1;  // Genesis at top
                const xOffset = isGenesis ? 50 : 50 + (idx - 1) * 320;
                const yOffset = level * 200 + 20;
                
                nodePositions[chain.merkle_root] = { x: xOffset + 140, y: yOffset + 80 };
                
                const node = document.createElement('div');
                node.className = `chain-node ${isGenesis ? 'genesis' : ''}`;
                node.style.left = xOffset + 'px';
                node.style.top = yOffset + 'px';
                node.onclick = () => selectChain(chain);
                
                const recordCount = Object.keys(chain.records || {}).length;
                // Handle timestamp - could be number (unix), string (ISO), or missing
                let timestamp = 'Unknown';
                if (chain.created_at) {
                    if (typeof chain.created_at === 'number') {
                        timestamp = new Date(chain.created_at * 1000).toLocaleString();
                    } else if (typeof chain.created_at === 'string') {
                        const d = new Date(chain.created_at);
                        timestamp = isNaN(d.getTime()) ? chain.created_at : d.toLocaleString();
                    }
                }
                
                node.innerHTML = `
                    <div class="node-header">
                        <span class="node-name">${chain.name}</span>
                        <span class="node-type">${isGenesis ? 'ORIGIN' : 'AGENT'}</span>
                    </div>
                    <div class="merkle-root">${chain.merkle_root}</div>
                    <div class="cid">
                        <a href="https://storacha.link/ipfs/${chain.cid}" target="_blank">${chain.cid ? chain.cid.slice(0, 20) + '...' : 'No CID'}</a>
                    </div>
                    <div class="node-stats">
                        <span>📊 ${recordCount} records</span>
                        <span>🕐 ${timestamp}</span>
                    </div>
                `;
                
                canvas.appendChild(node);
            });
            
            // Draw connections
            chains.forEach(chain => {
                if (chain.parent_root && nodePositions[chain.parent_root]) {
                    const from = nodePositions[chain.parent_root];
                    const to = nodePositions[chain.merkle_root];
                    if (from && to) {
                        drawConnection(canvas, from, to);
                    }
                }
            });
        }
        
        function drawConnection(canvas, from, to) {
            const line = document.createElement('div');
            line.className = 'connection-line';
            line.style.left = '0';
            line.style.top = '0';
            line.style.width = '100%';
            line.style.height = '100%';
            
            const dx = to.x - from.x;
            const dy = to.y - from.y;
            
            line.innerHTML = `
                <svg width="100%" height="100%">
                    <path d="M ${from.x} ${from.y} C ${from.x} ${from.y + dy/2}, ${to.x} ${to.y - dy/2}, ${to.x} ${to.y}" />
                </svg>
            `;
            
            canvas.insertBefore(line, canvas.firstChild);
        }
        
        function selectChain(chain) {
            selectedChain = chain;
            
            // Update selection visual
            document.querySelectorAll('.chain-node').forEach(n => n.classList.remove('selected'));
            event.currentTarget.classList.add('selected');
            
            // Build detail view
            const details = document.getElementById('chain-details');
            const records = chain.records || {};
            const recordNames = Object.keys(records);
            
            // Build lineage trail
            let lineageHtml = '<div class="lineage-trail">';
            if (chain.parent_root) {
                lineageHtml += `
                    <div class="lineage-step">
                        <span class="step-name genesis">genesis</span>
                        <span class="arrow">→</span>
                    </div>
                `;
            }
            lineageHtml += `
                <div class="lineage-step">
                    <span class="step-name">${chain.name}</span>
                </div>
            `;
            lineageHtml += '</div>';
            
            details.innerHTML = `
                ${lineageHtml}
                
                <div class="detail-section">
                    <div class="detail-label">Merkle Root</div>
                    <div class="detail-value mono">${chain.merkle_root}</div>
                </div>
                
                <div class="detail-section">
                    <div class="detail-label">IPFS CID</div>
                    <div class="detail-value mono link" onclick="window.open('https://storacha.link/ipfs/${chain.cid}', '_blank')">
                        ${chain.cid || 'Not pinned'}
                    </div>
                </div>
                
                <div class="detail-section">
                    <div class="detail-label">Model</div>
                    <div class="detail-value">${chain.model_id || 'Unknown'}</div>
                </div>
                
                <div class="detail-section">
                    <div class="detail-label">Records (${recordNames.length})</div>
                    <div class="records-list">
                        ${recordNames.map(name => {
                            const rec = records[name];
                            return `
                                <div class="record-item" onclick="showRecord('${name}')">
                                    <div class="record-name">${name}</div>
                                    <div class="record-hash">${rec.state_hash || 'N/A'}</div>
                                </div>
                            `;
                        }).join('')}
                    </div>
                </div>
                
                <div class="detail-section">
                    <div class="detail-label">External Links</div>
                    <div class="detail-value">
                        ${(chain.external_roots || []).length > 0 
                            ? chain.external_roots.map(r => `<code>${r}</code>`).join('<br>') 
                            : 'None'}
                    </div>
                </div>
                
                <div class="detail-section">
                    <div class="detail-label">Created</div>
                    <div class="detail-value">${chain.created_at ? new Date(chain.created_at * 1000).toLocaleString() : 'Unknown'}</div>
                </div>
            `;
        }
        
        function showRecord(name) {
            if (!selectedChain || !selectedChain.records) return;
            const rec = selectedChain.records[name];
            if (!rec) return;
            
            alert(JSON.stringify(rec, null, 2));
        }
        
        function resolveCID() {
            const input = document.getElementById('cid-input');
            const cid = input.value.trim();
            if (!cid) return;
            
            // Open in new tab via IPFS gateway
            window.open(`https://storacha.link/ipfs/${cid}`, '_blank');
        }
        
        // Initialize on load
        document.addEventListener('DOMContentLoaded', initLattice);
        initLattice();
    </script>
</body>
</html>
"""


def load_lattice_data(lattice_dir: Path = None) -> Dict[str, Any]:
    """
    Load lattice data from files for visualization.
    """
    if lattice_dir is None:
        lattice_dir = Path(__file__).resolve().parent.parent.parent / "lattice"
    
    ipld_dir = lattice_dir / "ipld"
    chains = []
    
    # Load from IPLD files first (they have CIDs)
    if ipld_dir.exists():
        for ipld_json in ipld_dir.glob("*.ipld.json"):
            try:
                meta = json.loads(ipld_json.read_text())
                name = ipld_json.stem.replace('.ipld', '')
                
                # Load the full chain data from CBOR if available
                cbor_file = ipld_dir / f"{name}.cbor"
                
                chain_data = {}
                if cbor_file.exists() and HAS_DAG_CBOR:
                    try:
                        chain_data = dag_cbor.decode(cbor_file.read_bytes())
                    except:
                        pass
                
                # Merge metadata - prefer CBOR data, fall back to IPLD JSON metadata
                # The .ipld.json file contains records too, so use that if CBOR failed
                chain = {
                    'name': name,
                    'cid': meta.get('_cid') or meta.get('cid'),
                    'merkle_root': meta.get('merkle_root') or chain_data.get('merkle_root'),
                    'model_id': meta.get('model_id') or chain_data.get('model_id'),
                    'created_at': meta.get('created_at') or chain_data.get('created_at'),
                    'records': chain_data.get('records') or meta.get('records', {}),
                    'external_roots': chain_data.get('external_roots') or meta.get('external_roots', []),
                    'parent_root': None,  # Will be detected from external_roots
                }
                
                # If this chain links to genesis, mark it
                if chain['external_roots']:
                    # First external root is typically the parent
                    chain['parent_root'] = chain['external_roots'][0] if chain['external_roots'] else None
                
                chains.append(chain)
            except Exception as e:
                print(f"Error loading {ipld_json}: {e}")
    
    # Also load from JSON files
    for json_file in lattice_dir.glob("*.json"):
        if json_file.name == "README.md":
            continue
        # Skip non-chain files
        if json_file.name in ("observation_index.json",):
            continue
        try:
            chain_data = json.loads(json_file.read_text())
            name = json_file.stem
            
            # Skip if it doesn't look like a chain (no merkle_root or records)
            if not chain_data.get('merkle_root') and not chain_data.get('records') and not chain_data.get('chain'):
                continue
            
            # Skip if we already have this from IPLD
            if any(c['name'] == name for c in chains):
                continue
            
            # Handle different chain formats
            records = chain_data.get('records', {})
            if not records and chain_data.get('chain'):
                # cascade_alpha_full format: has 'chain' with records inside
                inner_chain = chain_data.get('chain', {})
                records = inner_chain.get('records', {})
            
            chain = {
                'name': name,
                'cid': None,
                'merkle_root': chain_data.get('merkle_root'),
                'model_id': chain_data.get('model_id') or chain_data.get('model'),
                'created_at': chain_data.get('created_at') or chain_data.get('timestamp'),
                'records': records,
                'external_roots': chain_data.get('external_roots', []),
                'parent_root': chain_data.get('external_roots', [None])[0] if chain_data.get('external_roots') else None,
            }
            chains.append(chain)
        except Exception as e:
            print(f"Error loading {json_file}: {e}")
    
    # Sort: genesis first, then by creation time
    def sort_key(c):
        is_genesis = 0 if c['name'] == 'genesis' else 1
        created = c.get('created_at')
        if created is None:
            created = 0
        elif isinstance(created, str):
            try:
                from datetime import datetime
                created = datetime.fromisoformat(created.replace('Z', '+00:00')).timestamp()
            except:
                created = 0
        return (is_genesis, created or 0)
    
    chains.sort(key=sort_key)
    
    return {
        'chains': chains,
        'genesis_root': next((c['merkle_root'] for c in chains if c['name'] == 'genesis'), None),
    }


def build_lattice_gateway_html(lattice_dir: Path = None) -> str:
    """
    Build the complete lattice gateway HTML with embedded data.
    """
    # Load lattice data
    data = load_lattice_data(lattice_dir)
    
    # Debug: print what we loaded
    print(f"[LATTICE] Loaded {len(data.get('chains', []))} chains for HTML visualization")
    for c in data.get('chains', []):
        print(f"[LATTICE]   - {c['name']}: {len(c.get('records', {}))} records")
    
    # Fallback: ensure we have genesis even if files not found
    if not data.get('chains'):
        data = {
            'chains': [{
                'name': 'genesis',
                'merkle_root': '89f940c1a4b7aa65',
                'cid': 'bafkreidixjlzdat7ex72foi6vm3vnskhzguovxj6ondbazrqks7v6ahmei',
                'model_id': 'cascade_genesis',
                'created_at': 1767492437.5,
                'records': {'genesis': {'layer_name': 'genesis', 'dtype': 'genesis'}},
                'external_roots': [],
            }],
            'genesis_root': '89f940c1a4b7aa65',
        }
        print("[LATTICE] Using fallback genesis data")
    
    # Get the HTML template
    html = get_lattice_html()
    
    # Inject the data
    html = html.replace('LATTICE_DATA_PLACEHOLDER', json.dumps(data))
    
    return html


def create_gradio_lattice_tab():
    """
    Create Gradio components for the lattice gateway tab.
    Returns the components needed to integrate into the main app.
    """
    import gradio as gr
    
    # Load initial data
    lattice_data = load_lattice_data()
    chains = lattice_data.get('chains', [])
    
    def resolve_cid(cid: str) -> tuple:
        """Resolve a CID and return formatted content."""
        if not cid or not cid.strip():
            return "Enter a CID to resolve", ""
        
        cid = cid.strip()
        
        # Try to find in local lattice
        for chain in chains:
            if chain.get('cid') == cid:
                return (
                    f"✅ **{chain['name']}** found locally",
                    f"```json\n{json.dumps(chain, indent=2, default=str)}\n```"
                )
        
        # Return gateway link
        gateway_url = f"https://storacha.link/ipfs/{cid}"
        return (
            f"🌐 Not in local lattice. [View on IPFS Gateway]({gateway_url})",
            f"Gateway URL: {gateway_url}"
        )
    
    def get_chain_details(chain_name: str) -> str:
        """Get details for a specific chain."""
        if not chain_name:
            return "Select a chain to view details"
        
        # Re-load chains to ensure we have latest data
        current_data = load_lattice_data()
        current_chains = current_data.get('chains', [])
        
        chain = next((c for c in current_chains if c['name'] == chain_name), None)
        if not chain:
            return f"Chain '{chain_name}' not found. Available: {[c['name'] for c in current_chains]}"
        
        # Handle created_at which might be float, int, or string
        created_str = "Unknown"
        created_at = chain.get('created_at')
        if created_at:
            try:
                if isinstance(created_at, (int, float)):
                    created_str = datetime.fromtimestamp(created_at).isoformat()
                elif isinstance(created_at, str):
                    # Already a string, use as-is or parse
                    created_str = created_at
            except:
                created_str = str(created_at)
        
        return f"""
## {chain['name']}

**Merkle Root:** `{chain.get('merkle_root', 'N/A')}`

**IPFS CID:** `{chain.get('cid', 'Not pinned')}`

**Model:** {chain.get('model_id', 'Unknown')}

**Records:** {len(chain.get('records', {}))}

**Created:** {created_str}

### Records
```json
{json.dumps(chain.get('records', {}), indent=2, default=str)}
```

### External Links
{', '.join([f'`{r}`' for r in chain.get('external_roots', [])]) or 'None'}
"""
    
    def refresh_lattice():
        """Refresh lattice data."""
        import gradio as gr
        nonlocal chains, lattice_data
        lattice_data = load_lattice_data()
        chains = lattice_data.get('chains', [])
        
        chain_choices = [c['name'] for c in chains]
        default_value = chain_choices[0] if chain_choices else None
        
        return (
            gr.Dropdown(choices=chain_choices, value=default_value),
            f"**{len(chains)} chains** in lattice | Genesis: `{lattice_data.get('genesis_root', 'N/A')}`"
        )
    
    # Initial chain choices - simple strings, not tuples
    chain_choices = [c['name'] for c in chains]
    
    return {
        'resolve_cid': resolve_cid,
        'get_chain_details': get_chain_details,
        'refresh_lattice': refresh_lattice,
        'initial_chains': chain_choices,
        'initial_status': f"**{len(chains)} chains** in lattice | Genesis: `{lattice_data.get('genesis_root', 'N/A')}`",
    }


if __name__ == "__main__":
    # Test: generate HTML
    html = build_lattice_gateway_html()
    output = Path(__file__).parent.parent.parent / "lattice_gateway_test.html"
    output.write_text(html)
    print(f"Generated: {output}")
