#!/usr/bin/env python3
"""
Novyx Core - Interactive Dashboard
===================================
Web UI for semantic knowledge graph management using Streamlit.

Features:
- Artifact ingestion via file upload
- Semantic search with visual results
- Knowledge graph statistics
- Integrity verification
- Linked artifacts visualization

Usage:
    streamlit run tools/dashboard.py
"""

import streamlit as st
import json
import sys
from pathlib import Path
from datetime import datetime
import hashlib

# Add tools directory to path for imports
sys.path.insert(0, str(Path(__file__).parent))

# Import Novyx Core tools
try:
    from ingestor import SemanticPulse
    from query import QueryEngine
    from sentinel import NovyxSentinel
    TOOLS_AVAILABLE = True
except ImportError as e:
    TOOLS_AVAILABLE = False
    IMPORT_ERROR = str(e)

# Configuration
MEMORY_DIR = Path("memory")
CATEGORIES = ["research", "health", "decisions", "inbox"]

# Page config
st.set_page_config(
    page_title="Novyx Core Dashboard",
    page_icon="🧠",
    layout="wide",
    initial_sidebar_state="expanded"
)

# Custom CSS for better styling
st.markdown("""
<style>
    .main-header {
        font-size: 3rem;
        font-weight: 800;
        background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        margin-bottom: 0.5rem;
    }
    .sub-header {
        color: #666;
        font-size: 1.2rem;
        margin-bottom: 2rem;
    }
    .stat-card {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        padding: 1.5rem;
        border-radius: 10px;
        color: white;
        text-align: center;
    }
    .stat-value {
        font-size: 2.5rem;
        font-weight: bold;
        margin: 0.5rem 0;
    }
    .stat-label {
        font-size: 0.9rem;
        opacity: 0.9;
    }
    .artifact-card {
        border: 1px solid #e0e0e0;
        border-radius: 10px;
        padding: 1.5rem;
        margin: 1rem 0;
        background: #f9f9f9;
    }
    .link-badge {
        display: inline-block;
        background: #667eea;
        color: white;
        padding: 0.3rem 0.8rem;
        border-radius: 15px;
        font-size: 0.85rem;
        margin: 0.2rem;
    }
    .success-box {
        background: #d4edda;
        border: 1px solid #c3e6cb;
        color: #155724;
        padding: 1rem;
        border-radius: 5px;
        margin: 1rem 0;
    }
    .error-box {
        background: #f8d7da;
        border: 1px solid #f5c6cb;
        color: #721c24;
        padding: 1rem;
        border-radius: 5px;
        margin: 1rem 0;
    }
    .warning-box {
        background: #fff3cd;
        border: 1px solid #ffeaa7;
        color: #856404;
        padding: 1rem;
        border-radius: 5px;
        margin: 1rem 0;
    }
</style>
""", unsafe_allow_html=True)


def render_header():
    """Render dashboard header."""
    st.markdown('<h1 class="main-header">🧠 Novyx Core</h1>', unsafe_allow_html=True)
    st.markdown('<p class="sub-header">Persistent Intelligence Dashboard • Local-First Knowledge Graph</p>', unsafe_allow_html=True)
    st.markdown("---")


def render_sidebar():
    """Render sidebar with navigation and info."""
    with st.sidebar:
        st.image("https://via.placeholder.com/300x100/667eea/ffffff?text=Novyx+Labs", use_container_width=True)
        
        st.markdown("### 🎯 Dashboard")
        
        page = st.radio(
            "Navigation",
            ["📊 Overview", "📥 Ingest", "🔍 Search", "🛡️ Integrity", "📚 Browse", "🧭 Decisions", "⚖️ Legal"],
            label_visibility="collapsed"
        )
        
        st.markdown("---")
        
        st.markdown("### ⚙️ System Status")
        
        if TOOLS_AVAILABLE:
            st.success("✅ All tools loaded")
        else:
            st.error(f"❌ Import error: {IMPORT_ERROR}")
        
        # Show memory directory status
        if MEMORY_DIR.exists():
            artifact_count = len(list(MEMORY_DIR.rglob("*.jsonld")))
            st.info(f"📁 {artifact_count} artifacts")
        else:
            st.warning("📁 Memory dir not found")
        
        st.markdown("---")
        
        st.markdown("### 🔗 Quick Links")
        st.markdown("- [GitHub](https://github.com/novyxlabs/novyx-core)")
        st.markdown("- [Schema](../CORE_SCHEMA.jsonld)")
        st.markdown("- [Manifesto](../agents/MANIFESTO.md)")
        
        st.markdown("---")
        st.caption("v1.1.0 • Local-First • No Cloud")
        
    return page


def render_overview():
    """Render overview page with statistics."""
    st.header("📊 Knowledge Graph Overview")
    
    if not TOOLS_AVAILABLE:
        st.error("⚠️ Cannot load overview. Tools not available.")
        return
    
    try:
        # Initialize query engine
        query_engine = QueryEngine(strict=False, force_no_embeddings=False)
        
        # Get statistics
        total = len(query_engine.artifacts)
        
        # Category breakdown
        categories = {}
        for artifact in query_engine.artifacts:
            cat = artifact.get('category', 'unknown')
            categories[cat] = categories.get(cat, 0) + 1
        
        # Count semantic links
        total_links = sum(len(a.get('links', [])) for a in query_engine.artifacts)
        
        # Count authority links
        total_authorities = sum(len(a.get('sameAs', [])) for a in query_engine.artifacts)
        
        # Display stats in columns
        col1, col2, col3, col4 = st.columns(4)
        
        with col1:
            st.markdown(f"""
            <div class="stat-card">
                <div class="stat-label">Total Artifacts</div>
                <div class="stat-value">{total}</div>
            </div>
            """, unsafe_allow_html=True)
        
        with col2:
            st.markdown(f"""
            <div class="stat-card" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);">
                <div class="stat-label">Categories</div>
                <div class="stat-value">{len(categories)}</div>
            </div>
            """, unsafe_allow_html=True)
        
        with col3:
            st.markdown(f"""
            <div class="stat-card" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
                <div class="stat-label">Semantic Links</div>
                <div class="stat-value">{total_links}</div>
            </div>
            """, unsafe_allow_html=True)
        
        with col4:
            st.markdown(f"""
            <div class="stat-card" style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);">
                <div class="stat-label">Authority Links</div>
                <div class="stat-value">{total_authorities}</div>
            </div>
            """, unsafe_allow_html=True)
        
        st.markdown("<br>", unsafe_allow_html=True)
        
        # Category breakdown chart
        col1, col2 = st.columns([2, 1])
        
        with col1:
            st.subheader("📂 Category Distribution")
            if categories:
                st.bar_chart(categories)
            else:
                st.info("No artifacts yet. Use the **Ingest** page to add your first artifact!")
        
        with col2:
            st.subheader("📋 Categories")
            for cat, count in sorted(categories.items(), key=lambda x: x[1], reverse=True):
                st.metric(cat.title(), count)
        
        # Recent artifacts
        st.subheader("🕐 Recent Artifacts")
        
        if query_engine.artifacts:
            # Sort by path modification time (proxy for recent)
            recent = sorted(query_engine.artifacts, key=lambda x: x.get('path', ''), reverse=True)[:5]
            
            for artifact in recent:
                with st.expander(f"📄 {artifact.get('name', 'Untitled')}"):
                    st.markdown(f"**UUID:** `{artifact.get('uuid', 'N/A')}`")
                    st.markdown(f"**Category:** {artifact.get('category', 'unknown')}")
                    st.markdown(f"**Content:** {artifact.get('content', '')[:200]}...")
                    
                    if artifact.get('sameAs'):
                        st.markdown("**External Authorities:**")
                        for auth in artifact['sameAs']:
                            st.markdown(f"- 🌐 [{auth}]({auth})")
                    
                    if artifact.get('links'):
                        st.markdown(f"**Semantic Links:** {len(artifact['links'])} connections")
        else:
            st.info("No artifacts yet. Start by ingesting your first document!")
    
    except Exception as e:
        st.error(f"Error loading overview: {str(e)}")


def render_ingest():
    """Render artifact ingestion page."""
    st.header("📥 Ingest New Artifact")
    
    if not TOOLS_AVAILABLE:
        st.error("⚠️ Cannot ingest artifacts. Tools not available.")
        st.code(f"Error: {IMPORT_ERROR}", language="text")
        return
    
    st.markdown("""
    Upload a text file to create a new artifact in the knowledge graph.
    The system will automatically:
    - Generate a unique UUID
    - Create 384-dimensional embeddings
    - Link to the top 3 most similar artifacts
    - Compute SHA-256 integrity hash
    """)
    
    col1, col2 = st.columns([2, 1])
    
    with col1:
        # File upload
        uploaded_file = st.file_uploader(
            "Choose a text file",
            type=['txt', 'md', 'text'],
            help="Upload a plain text or markdown file"
        )
    
    with col2:
        # Category selection
        category = st.selectbox(
            "Category",
            CATEGORIES,
            help="Organize your artifact by category"
        )
        
        # External authority (optional)
        authority_link = st.text_input(
            "External Authority (optional)",
            placeholder="https://github.com/username",
            help="Link to GitHub, LinkedIn, ORCID, etc."
        )
    
    # Ingest button
    if st.button("🚀 Ingest Artifact", type="primary", use_container_width=True):
        if uploaded_file is None:
            st.warning("⚠️ Please upload a file first.")
        else:
            with st.spinner("Processing artifact..."):
                try:
                    # Read file content
                    content = uploaded_file.read().decode('utf-8')
                    
                    # Save to temporary file
                    temp_path = Path(f"temp_{uploaded_file.name}")
                    temp_path.write_text(content)
                    
                    # Initialize Semantic Pulse
                    pulse = SemanticPulse(strict=False, force_no_embeddings=False)
                    
                    # Ingest the artifact
                    result = pulse.ingest(
                        file_path=temp_path,
                        category=category,
                        external_links=[authority_link] if authority_link else None
                    )
                    
                    # Clean up temp file
                    temp_path.unlink()
                    
                    # Display success
                    st.markdown(f"""
                    <div class="success-box">
                        <h4>✅ Artifact Ingested Successfully!</h4>
                        <p><strong>UUID:</strong> <code>{result['uuid']}</code></p>
                        <p><strong>Category:</strong> {category}</p>
                        <p><strong>Hash:</strong> <code>{result['hash'][:16]}...</code></p>
                        <p><strong>Semantic Links:</strong> {len(result.get('links', []))} connections found</p>
                    </div>
                    """, unsafe_allow_html=True)
                    
                    # Show linked artifacts
                    if result.get('links'):
                        st.subheader("🔗 Automatically Linked Artifacts")
                        for link in result['links']:
                            score = link.get('confidenceScore', 0)
                            st.markdown(f"""
                            <div class="artifact-card">
                                <strong>Target:</strong> <code>{link.get('targetId', 'N/A')[:40]}...</code><br>
                                <strong>Confidence:</strong> <span class="link-badge">{score:.2%}</span><br>
                                <strong>Rationale:</strong> {link.get('rationale', 'N/A')}
                            </div>
                            """, unsafe_allow_html=True)
                    
                    # Show file path
                    if result.get('path'):
                        st.info(f"📁 Saved to: `{result['path']}`")
                    
                    st.balloons()
                
                except Exception as e:
                    st.markdown(f"""
                    <div class="error-box">
                        <h4>❌ Ingestion Failed</h4>
                        <p>{str(e)}</p>
                    </div>
                    """, unsafe_allow_html=True)
                    st.exception(e)


def render_search():
    """Render semantic search page."""
    st.header("🔍 Semantic Search")
    
    if not TOOLS_AVAILABLE:
        st.error("⚠️ Cannot perform search. Tools not available.")
        return
    
    st.markdown("""
    Search by **meaning**, not just keywords. The system uses 384-dimensional embeddings
    to find semantically similar artifacts based on cosine similarity.
    """)
    
    # Search input
    query = st.text_input(
        "Enter your search query",
        placeholder="e.g., 'AI agents and cognitive science'",
        help="Natural language queries work best"
    )
    
    col1, col2 = st.columns([1, 1])
    
    with col1:
        # Minimum similarity threshold
        min_similarity = st.slider(
            "Minimum Similarity",
            min_value=0.0,
            max_value=1.0,
            value=0.2,
            step=0.05,
            help="Lower = more results, higher = more precise"
        )
    
    with col2:
        # Max results
        max_results = st.number_input(
            "Max Results",
            min_value=1,
            max_value=50,
            value=10,
            help="Maximum number of results to display"
        )
    
    # Search button
    if st.button("🔍 Search", type="primary", use_container_width=True):
        if not query:
            st.warning("⚠️ Please enter a search query.")
        else:
            with st.spinner("Searching knowledge graph..."):
                try:
                    # Initialize query engine
                    query_engine = QueryEngine(strict=False, force_no_embeddings=False)
                    
                    # Perform semantic search
                    results = query_engine.semantic_search(query, top_k=max_results)
                    
                    # Filter by minimum similarity
                    results = [r for r in results if r['score'] >= min_similarity]
                    
                    # Display results
                    st.subheader(f"📊 Found {len(results)} Results")
                    
                    if not results:
                        st.info("No results found. Try lowering the similarity threshold or using different keywords.")
                    else:
                        for i, result in enumerate(results, 1):
                            score = result['score']
                            artifact = result['artifact']
                            
                            # Color code by score
                            if score >= 0.7:
                                color = "#43e97b"
                                label = "High Match"
                            elif score >= 0.4:
                                color = "#4facfe"
                                label = "Good Match"
                            else:
                                color = "#f093fb"
                                label = "Weak Match"
                            
                            with st.expander(f"**{i}. {artifact.get('name', 'Untitled')}** ({score:.2%} - {label})"):
                                st.markdown(f"**UUID:** `{artifact.get('uuid', 'N/A')}`")
                                st.markdown(f"**Category:** {artifact.get('category', 'unknown')}")
                                st.markdown(f"**Path:** `{artifact.get('path', 'N/A')}`")
                                
                                st.markdown("**Content Preview:**")
                                st.text(artifact.get('content', '')[:300] + "..." if len(artifact.get('content', '')) > 300 else artifact.get('content', ''))
                                
                                # Show semantic links
                                if artifact.get('links'):
                                    st.markdown(f"**Connections:** {len(artifact['links'])} semantic links")
                                
                                # Show external authorities
                                if artifact.get('sameAs'):
                                    st.markdown("**External Authorities:**")
                                    for auth in artifact['sameAs']:
                                        st.markdown(f"- 🌐 [{auth}]({auth})")
                
                except Exception as e:
                    st.error(f"Search failed: {str(e)}")
                    st.exception(e)


def render_integrity():
    """Render integrity verification page."""
    st.header("🛡️ Integrity Verification")
    
    if not TOOLS_AVAILABLE:
        st.error("⚠️ Cannot run integrity checks. Tools not available.")
        return
    
    st.markdown("""
    Verify the cryptographic integrity of all artifacts in the knowledge graph.
    The Sentinel auditor checks:
    - SHA-256 hash validation
    - Required fields presence
    - Cross-domain context linkage
    - Temporal marker validity
    """)
    
    col1, col2 = st.columns([1, 1])
    
    with col1:
        verbose = st.checkbox("Verbose Output", value=False, help="Show detailed check results")
    
    with col2:
        directory = st.text_input(
            "Directory to Check",
            value="memory",
            help="Relative path from repo root"
        )
    
    # Run integrity check button
    if st.button("🛡️ Run Integrity Check", type="primary", use_container_width=True):
        with st.spinner("Verifying integrity..."):
            try:
                # Initialize Sentinel
                sentinel = NovyxSentinel(
                    root_dir=Path(directory),
                    verbose=verbose
                )
                
                # Find all artifacts
                artifacts = list(Path(directory).rglob("*.jsonld"))
                
                if not artifacts:
                    st.warning(f"⚠️ No artifacts found in `{directory}/`")
                    return
                
                st.info(f"🔍 Checking {len(artifacts)} artifacts...")
                
                # Validate each artifact
                all_passed = True
                results = []
                
                progress_bar = st.progress(0)
                
                for i, artifact_path in enumerate(artifacts):
                    # Load and validate
                    data, errors = sentinel.load_jsonld(artifact_path)
                    
                    if errors:
                        all_passed = False
                        results.append({
                            'path': str(artifact_path),
                            'status': 'error',
                            'message': ', '.join(errors)
                        })
                    else:
                        # Validate required fields
                        checks, field_errors = sentinel.validate_required_fields(data, str(artifact_path))
                        
                        # Calculate expected hash
                        expected_hash = sentinel.calculate_hash(artifact_path)
                        stored_hash = data.get('novyx:integrityHash') or data.get('Integrity_Hash')
                        
                        hash_valid = (expected_hash == stored_hash)
                        
                        if not hash_valid or field_errors:
                            all_passed = False
                            status = 'error'
                            message = "Hash mismatch" if not hash_valid else ', '.join(field_errors)
                        else:
                            status = 'success'
                            message = "All checks passed"
                        
                        results.append({
                            'path': str(artifact_path),
                            'status': status,
                            'message': message,
                            'checks': checks
                        })
                    
                    progress_bar.progress((i + 1) / len(artifacts))
                
                progress_bar.empty()
                
                # Display results
                if all_passed:
                    st.markdown(f"""
                    <div class="success-box">
                        <h3>✅ All Integrity Checks Passed!</h3>
                        <p>Verified {len(artifacts)} artifacts</p>
                        <p>• All SHA-256 hashes valid</p>
                        <p>• All required fields present</p>
                        <p>• No orphaned links detected</p>
                    </div>
                    """, unsafe_allow_html=True)
                    st.balloons()
                else:
                    failed_count = sum(1 for r in results if r['status'] == 'error')
                    st.markdown(f"""
                    <div class="error-box">
                        <h3>❌ Integrity Violations Detected</h3>
                        <p>{failed_count} of {len(artifacts)} artifacts failed validation</p>
                    </div>
                    """, unsafe_allow_html=True)
                
                # Show detailed results if verbose
                if verbose:
                    st.subheader("📋 Detailed Results")
                    
                    for result in results:
                        if result['status'] == 'success':
                            st.success(f"✅ {result['path']}")
                        else:
                            st.error(f"❌ {result['path']}: {result['message']}")
                
                # Summary metrics
                st.markdown("---")
                col1, col2, col3 = st.columns(3)
                
                with col1:
                    passed = sum(1 for r in results if r['status'] == 'success')
                    st.metric("Passed", passed)
                
                with col2:
                    failed = sum(1 for r in results if r['status'] == 'error')
                    st.metric("Failed", failed)
                
                with col3:
                    success_rate = (passed / len(results) * 100) if results else 0
                    st.metric("Success Rate", f"{success_rate:.1f}%")
            
            except Exception as e:
                st.error(f"Integrity check failed: {str(e)}")
                st.exception(e)


def render_browse():
    """Render artifact browsing page."""
    st.header("📚 Browse Artifacts")
    
    if not TOOLS_AVAILABLE:
        st.error("⚠️ Cannot browse artifacts. Tools not available.")
        return
    
    try:
        # Initialize query engine
        query_engine = QueryEngine(strict=False, force_no_embeddings=False)
        
        if not query_engine.artifacts:
            st.info("No artifacts yet. Use the **Ingest** page to add your first artifact!")
            return
        
        # Filters
        col1, col2 = st.columns([1, 1])
        
        with col1:
            # Category filter
            all_categories = list(set(a.get('category', 'unknown') for a in query_engine.artifacts))
            selected_category = st.selectbox(
                "Filter by Category",
                ["All"] + sorted(all_categories)
            )
        
        with col2:
            # Sort order
            sort_by = st.selectbox(
                "Sort By",
                ["Name", "Category", "Links Count"]
            )
        
        # Filter artifacts
        artifacts = query_engine.artifacts
        if selected_category != "All":
            artifacts = [a for a in artifacts if a.get('category') == selected_category]
        
        # Sort artifacts
        if sort_by == "Name":
            artifacts = sorted(artifacts, key=lambda x: x.get('name', 'Untitled'))
        elif sort_by == "Category":
            artifacts = sorted(artifacts, key=lambda x: x.get('category', 'unknown'))
        elif sort_by == "Links Count":
            artifacts = sorted(artifacts, key=lambda x: len(x.get('links', [])), reverse=True)
        
        st.markdown(f"**Showing {len(artifacts)} artifacts**")
        
        # Display artifacts
        for artifact in artifacts:
            with st.expander(f"📄 {artifact.get('name', 'Untitled')} ({artifact.get('category', 'unknown')})"):
                col1, col2 = st.columns([2, 1])
                
                with col1:
                    st.markdown(f"**UUID:** `{artifact.get('uuid', 'N/A')}`")
                    st.markdown(f"**Path:** `{artifact.get('path', 'N/A')}`")
                    
                    st.markdown("**Content:**")
                    content = artifact.get('content', '')
                    if len(content) > 500:
                        st.text_area("", content, height=200, disabled=True, label_visibility="collapsed")
                    else:
                        st.text(content)
                
                with col2:
                    st.markdown("**Metadata**")
                    
                    # Category badge
                    st.markdown(f'<span class="link-badge">{artifact.get("category", "unknown")}</span>', unsafe_allow_html=True)
                    
                    # Links count
                    links_count = len(artifact.get('links', []))
                    st.metric("Semantic Links", links_count)
                    
                    # Authority links
                    if artifact.get('sameAs'):
                        st.markdown("**External Authorities:**")
                        for auth in artifact['sameAs']:
                            st.markdown(f"🌐 [{auth.split('/')[-1]}]({auth})")
                
                # Show semantic links
                if artifact.get('links'):
                    st.markdown("**🔗 Semantic Links:**")
                    for link in artifact['links']:
                        score = link.get('confidenceScore', 0)
                        target = link.get('targetId', 'N/A')
                        rationale = link.get('rationale', 'N/A')
                        
                        st.markdown(f"""
                        - **Target:** `{target[:40]}...`
                        - **Confidence:** {score:.2%}
                        - **Rationale:** {rationale}
                        """)
    
    except Exception as e:
        st.error(f"Error browsing artifacts: {str(e)}")
        st.exception(e)


def render_decisions():
    """Render Decision capture, browse, and integrity status."""
    st.header("🧭 Decisions (Layer 1: Causal Memory)")

    if not TOOLS_AVAILABLE:
        st.error("⚠️ Cannot manage decisions. Tools not available.")
        return

    st.markdown("Capture decisions with context, options, reasoning, and integrity hashes.")

    def _to_list(raw: str):
        if not raw:
            return []
        return [item.strip() for item in raw.replace(",", "\n").splitlines() if item.strip()]

    # Create Decision
    with st.expander("Create Decision", expanded=True):
        with st.form("decision_form"):
            title = st.text_input("Title", placeholder="e.g., Select vector DB for v1")
            context = st.text_area("Context / Problem", placeholder="What problem are you solving?")
            options_raw = st.text_area("Options considered (one per line or comma-separated)")
            chosen_option = st.text_input("Chosen option", placeholder="Pick the selected option")
            reasoning = st.text_area("Reasoning", placeholder="Why this option?")
            constraints_raw = st.text_area("Constraints (one per line)", value="")
            assumptions_raw = st.text_area("Assumptions (one per line)", value="")
            confidence_slider = st.slider("Confidence (0-1)", 0.0, 1.0, 0.6, step=0.05)
            confidence_label = st.text_input("Confidence label (optional, overrides slider)", value="")
            expected_outcome = st.text_area("Expected outcome", placeholder="What you expect to happen")
            category = st.text_input("Category", value="decisions")
            same_as_raw = st.text_input("External authority links (comma/newline)", placeholder="https://github.com/novyxlabs")

            submitted = st.form_submit_button("💾 Save Decision", use_container_width=True)

        if submitted:
            confidence = confidence_label.strip() or confidence_slider
            decision_payload = {
                "title": title,
                "context": context,
                "options_considered": _to_list(options_raw),
                "chosen_option": chosen_option,
                "reasoning": reasoning,
                "constraints": _to_list(constraints_raw),
                "assumptions": _to_list(assumptions_raw),
                "confidence": confidence,
                "expected_outcome": expected_outcome,
                "category": category or "decisions"
            }

            try:
                pulse = SemanticPulse(strict=False, force_no_embeddings=False)
                result = pulse.ingest_decision(decision_payload, _to_list(same_as_raw))
                st.success(f"✅ Decision saved: {result['path']}")
                st.markdown(f"- UUID: `{result['uuid']}`")
                st.markdown(f"- Hash: `{result['hash']}`")
                st.markdown(f"- Semantic links: {len(result.get('links', []))}")
            except Exception as e:
                st.error(f"Failed to save decision: {e}")
                st.exception(e)

    # Browse Decisions
    st.subheader("Browse Decisions")
    try:
        query_engine = QueryEngine(strict=False, force_no_embeddings=False)
        decisions = [a for a in query_engine.artifacts if a.get('category') == 'decisions']

        search_term = st.text_input("Search decisions (title/context/reasoning)", value="")
        if search_term:
            search_term_lower = search_term.lower()
            decisions = [
                a for a in decisions
                if search_term_lower in (a.get('name', '') + a.get('content', '')).lower()
            ]

        if not decisions:
            st.info("No decisions yet. Capture your first decision above.")
            return

        sentinel = NovyxSentinel(root_dir=MEMORY_DIR, verbose=False)

        for artifact in decisions:
            path = Path(artifact.get('path'))
            data, parse_errors = sentinel.load_jsonld(path)
            if parse_errors:
                st.error(f"❌ {artifact.get('name', 'Decision')} - parse error: {', '.join(parse_errors)}")
                continue

            stored_hash = data.get('novyx:integrityHash') or data.get('Integrity_Hash')
            integrity_ok = False
            try:
                calculated_hash = sentinel.calculate_hash(path)
                integrity_ok = stored_hash == calculated_hash
            except Exception:
                integrity_ok = False

            badge = "✅ Hash valid" if integrity_ok else "⚠️ Hash mismatch"

            with st.expander(f"📄 {artifact.get('name', 'Decision')} ({badge})"):
                st.markdown(f"**UUID:** `{data.get('uuid', 'N/A')}`")
                st.markdown(f"**Path:** `{path}`")
                st.markdown(f"**Chosen option:** {data.get('chosen_option', 'N/A')}")
                st.markdown(f"**Reasoning:** {data.get('reasoning', '')}")
                st.markdown(f"**Expected outcome:** {data.get('expected_outcome', '')}")
                st.markdown(f"**Confidence:** {data.get('confidence', 'N/A')}")
                st.markdown(f"**Created:** {data.get('createdAt') or data.get('novyx:ingestedAt')}")

                if data.get('options_considered'):
                    st.markdown("**Options considered:**")
                    st.write(data.get('options_considered'))
                if data.get('constraints'):
                    st.markdown("**Constraints:**")
                    st.write(data.get('constraints'))
                if data.get('assumptions'):
                    st.markdown("**Assumptions:**")
                    st.write(data.get('assumptions'))

                st.markdown(f"**Integrity:** {badge}")
    except Exception as e:
        st.error(f"Error loading decisions: {str(e)}")
        st.exception(e)


def generate_readable_document(doc_name: str, doc_data: dict, doc_type: str) -> str:
    """Generate human-readable HTML document from JSON data."""
    
    date_str = datetime.now().strftime('%B %d, %Y')
    
    html = f"""<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{doc_name}</title>
    <style>
        body {{
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            line-height: 1.6;
            max-width: 800px;
            margin: 40px auto;
            padding: 20px;
            color: #333;
        }}
        h1 {{
            color: #667eea;
            border-bottom: 3px solid #667eea;
            padding-bottom: 10px;
        }}
        h2 {{
            color: #764ba2;
            margin-top: 30px;
            border-bottom: 1px solid #ddd;
            padding-bottom: 5px;
        }}
        h3 {{
            color: #555;
            margin-top: 20px;
        }}
        .meta {{
            background: #f5f5f5;
            padding: 15px;
            border-radius: 5px;
            margin: 20px 0;
            border-left: 4px solid #667eea;
        }}
        .meta strong {{
            color: #667eea;
        }}
        ul {{
            padding-left: 25px;
        }}
        li {{
            margin: 8px 0;
        }}
        .assertion {{
            background: #e8f5e9;
            padding: 12px;
            margin: 10px 0;
            border-radius: 4px;
            border-left: 4px solid #43a047;
        }}
        .warning {{
            background: #fff3cd;
            padding: 12px;
            margin: 10px 0;
            border-radius: 4px;
            border-left: 4px solid #ffc107;
        }}
        .footer {{
            margin-top: 50px;
            padding-top: 20px;
            border-top: 2px solid #ddd;
            color: #666;
            font-size: 0.9em;
        }}
        .shareable {{
            background: #e3f2fd;
            padding: 15px;
            border-radius: 5px;
            margin: 15px 0;
            border-left: 4px solid #2196f3;
        }}
        table {{
            width: 100%;
            border-collapse: collapse;
            margin: 20px 0;
        }}
        th, td {{
            padding: 12px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }}
        th {{
            background: #667eea;
            color: white;
        }}
        @media print {{
            body {{ margin: 20px; }}
            .no-print {{ display: none; }}
        }}
    </style>
</head>
<body>
    <h1>{doc_name}</h1>
    <div class="meta">
        <strong>Generated:</strong> {date_str}<br>
"""
    
    # Add document-specific content
    if doc_type == "stripe_brief":
        html += f"""
        <strong>UUID:</strong> {doc_data.get('uuid', 'N/A')}<br>
        <strong>Integrity Hash:</strong> <code>{doc_data.get('novyx:integrityHash', 'N/A')[:32]}...</code>
    </div>
    
    <h2>📋 Entity Information</h2>
    <table>
        <tr><th>Field</th><th>Value</th></tr>
        <tr><td>Legal Name</td><td>{doc_data.get('entity', {}).get('name', 'N/A')}</td></tr>
        <tr><td>Jurisdiction</td><td>{doc_data.get('entity', {}).get('jurisdiction', 'N/A')}</td></tr>
        <tr><td>Type</td><td>{doc_data.get('entity', {}).get('type', 'N/A')}</td></tr>
    </table>
    
    <h2>🎯 Product Information</h2>
    <table>
        <tr><th>Field</th><th>Value</th></tr>
        <tr><td>Name</td><td>{doc_data.get('product', {}).get('name', 'N/A')}</td></tr>
        <tr><td>Category</td><td>{doc_data.get('product', {}).get('category', 'N/A')}</td></tr>
        <tr><td>Target Audience</td><td>{doc_data.get('product', {}).get('target_audience', 'N/A')}</td></tr>
        <tr><td>Business Model</td><td>{doc_data.get('product', {}).get('business_model', 'N/A')}</td></tr>
    </table>
    
    <h2>✅ COPPA Compliance</h2>
    <div class="assertion">
        <strong>Parental Consent:</strong> {doc_data.get('coppa_compliance', {}).get('parental_consent_mechanism', 'N/A')}<br>
        <strong>Third-Party Disclosure:</strong> {doc_data.get('coppa_compliance', {}).get('third_party_disclosure', 'N/A')}
    </div>
    
    <h3>Data Collected:</h3>
    <ul>
"""
        for item in doc_data.get('coppa_compliance', {}).get('data_collected', []):
            html += f"        <li>{item}</li>\n"
        
        html += f"""    </ul>
    
    <h3>Data NOT Collected:</h3>
    <ul>
"""
        for item in doc_data.get('coppa_compliance', {}).get('data_not_collected', []):
            html += f"        <li>✓ {item}</li>\n"
        
        html += f"""    </ul>
    
    <h2>🌍 GDPR Compliance</h2>
    <div class="assertion">
        <strong>Lawful Basis:</strong> {doc_data.get('gdpr_compliance', {}).get('lawful_basis', 'N/A')}<br>
        <strong>Data Minimization:</strong> {doc_data.get('gdpr_compliance', {}).get('data_minimization', 'N/A')}<br>
        <strong>Right to Access:</strong> {doc_data.get('gdpr_compliance', {}).get('right_to_access', 'N/A')}<br>
        <strong>Right to Erasure:</strong> {doc_data.get('gdpr_compliance', {}).get('right_to_erasure', 'N/A')}
    </div>
    
    <h2>💳 Payment Processing</h2>
    <table>
        <tr><th>Field</th><th>Value</th></tr>
        <tr><td>Processor</td><td>{doc_data.get('payment_processing', {}).get('processor', 'N/A')}</td></tr>
        <tr><td>PCI Compliance</td><td>{doc_data.get('payment_processing', {}).get('pci_compliance', 'N/A')}</td></tr>
        <tr><td>Refund Policy</td><td>{doc_data.get('payment_processing', {}).get('refund_policy', 'N/A')}</td></tr>
    </table>
    
    <h2>🔒 Verification Infrastructure</h2>
    <p><strong>Sentinel Status:</strong> {doc_data.get('verification_infrastructure', {}).get('sentinel_status', 'N/A')}</p>
    <p><strong>Integrity System:</strong> {doc_data.get('verification_infrastructure', {}).get('integrity_system', 'N/A')}</p>
"""
    
    elif doc_type == "privacy_policy":
        html += """
    </div>
    
    <h2>📜 Privacy Policy Overview</h2>
    <div class="assertion">
"""
        html += f"""
        <p><strong>COPPA Compliant:</strong> {'✓ Yes' if doc_data.get('coppaCompliance') else '✗ No'}</p>
        <p><strong>GDPR Compliant:</strong> {'✓ Yes' if doc_data.get('gdprCompliance') else '✗ No'}</p>
        <p><strong>Data Collection Policy:</strong> {doc_data.get('dataCollectionPolicy', 'N/A')}</p>
        <p><strong>Data Retention:</strong> {doc_data.get('dataRetentionPolicy', 'N/A')}</p>
        <p><strong>Third-Party Sharing:</strong> {doc_data.get('thirdPartyDataSharing', 'N/A')}</p>
    </div>
    
    <div class="warning">
        <strong>⚠️ Important:</strong> This is a machine-generated summary. Please review with legal counsel before public deployment.
    </div>
"""
    
    elif doc_type == "terms_of_service":
        html += """
    </div>
    
    <h2>📋 Terms of Service</h2>
"""
        html += f"""
    <p><strong>Age Requirement:</strong> {doc_data.get('ageRequirement', 'N/A')}</p>
    <p><strong>Service Type:</strong> {doc_data.get('serviceType', 'N/A')}</p>
    <p><strong>Payment Terms:</strong> {doc_data.get('paymentTerms', 'N/A')}</p>
    <p><strong>Refund Policy:</strong> {doc_data.get('refundPolicy', 'N/A')}</p>
    <p><strong>Intellectual Property:</strong> {doc_data.get('intellectualProperty', 'N/A')}</p>
"""
    
    elif doc_type == "parent_safety":
        html += """
    </div>
    
    <h2>🛡️ Parent Safety Guide</h2>
"""
        safety_pillars = doc_data.get('one_pager_content', {}).get('safety_pillars', [])
        for pillar in safety_pillars:
            html += f"""
    <h3>{pillar.get('concern', 'N/A')}</h3>
    <div class="assertion">
        <strong>Answer:</strong> {pillar.get('answer', 'N/A')}<br>
        <strong>Proof:</strong> {pillar.get('proof', 'N/A')}
    </div>
    <ul>
"""
            for detail in pillar.get('details', []):
                html += f"        <li>{detail}</li>\n"
            html += "    </ul>\n"
        
        shareable = doc_data.get('one_pager_content', {}).get('ShareableFormat', {})
        if shareable:
            html += """
    <h2>📱 Shareable Social Media Content</h2>
"""
            if 'Facebook_Post' in shareable:
                html += f"""
    <div class="shareable">
        <strong>Facebook Post:</strong><br>
        <p>{shareable['Facebook_Post']}</p>
    </div>
"""
            if 'Instagram_Caption' in shareable:
                html += f"""
    <div class="shareable">
        <strong>Instagram Caption:</strong><br>
        <p>{shareable['Instagram_Caption']}</p>
    </div>
"""
    
    # Footer
    html += f"""
    <div class="footer">
        <p><strong>Generated by:</strong> Novyx Legal Compliance Engine v1.0</p>
        <p><strong>Generated on:</strong> {date_str}</p>
        <p class="warning"><strong>⚠️ Important Notice:</strong> This document is machine-generated and should be reviewed by qualified legal counsel before use. This is not legal advice.</p>
        <p><strong>Cryptographic Verification:</strong> This document's integrity can be verified using the SHA-256 hash included in the JSON version.</p>
    </div>
    
    <div class="no-print" style="margin-top: 30px; padding: 20px; background: #f5f5f5; border-radius: 5px;">
        <h3>📥 How to Save as PDF:</h3>
        <ol>
            <li><strong>Chrome/Edge:</strong> Press Ctrl+P (or Cmd+P on Mac) → Select "Save as PDF" → Save</li>
            <li><strong>Firefox:</strong> Press Ctrl+P → Destination: "Save to PDF" → Save</li>
            <li><strong>Safari:</strong> Press Cmd+P → PDF dropdown → "Save as PDF"</li>
        </ol>
    </div>
</body>
</html>
"""
    
    return html


def render_legal():
    """Render legal compliance generation page."""
    st.header("⚖️ Legal Compliance Generator")
    
    st.markdown("""
    Auto-generate **COPPA/GDPR compliant** legal documents for your application.
    Documents are provided in both **human-readable** (HTML/PDF) and **machine-readable** (JSON) formats.
    """)
    
    # Initialize session state for generated documents
    if 'generated_docs' not in st.session_state:
        st.session_state.generated_docs = []
    
    # Import compliance engine functions
    try:
        sys.path.insert(0, str(Path(__file__).parent.parent / "spokes" / "legal_gen"))
        from compliance_engine import (
            generate_stripe_brief,
            generate_privacy_policy,
            generate_terms_of_service,
            generate_parent_safety_onepager
        )
        engine_available = True
    except ImportError as e:
        st.error(f"⚠️ Cannot load compliance engine: {e}")
        engine_available = False
        return
    
    # Input form
    st.subheader("📝 Application Details")
    
    col1, col2 = st.columns([2, 1])
    
    with col1:
        app_name = st.text_input(
            "Application Name",
            value="Indynigo",
            help="Your product/service name"
        )
        
        app_description = st.text_area(
            "Description",
            value="Educational AI platform for kids 7-16. Block coding, prompt engineering, and AI creativity.",
            help="Brief description of your application"
        )
    
    with col2:
        target_audience = st.text_input(
            "Target Audience",
            value="Children 7-16",
            help="Primary user demographic"
        )
        
        business_model = st.selectbox(
            "Business Model",
            ["Freemium SaaS", "Subscription Only", "One-Time Purchase", "Free/Open Source"],
            help="Your monetization approach"
        )
    
    # Advanced options (collapsible)
    with st.expander("⚙️ Advanced Options"):
        col1, col2 = st.columns(2)
        
        with col1:
            entity_name = st.text_input(
                "Legal Entity Name",
                value="Novyx Labs LLC",
                help="Your company's legal name"
            )
            
            jurisdiction = st.text_input(
                "Jurisdiction",
                value="United States",
                help="Primary operating jurisdiction"
            )
        
        with col2:
            payment_processor = st.selectbox(
                "Payment Processor",
                ["Stripe", "PayPal", "Square", "None"],
                help="If applicable"
            )
            
            refund_policy = st.text_input(
                "Refund Policy",
                value="30-day money-back guarantee",
                help="Your refund terms"
            )
    
    # Document selection
    st.subheader("📄 Documents to Generate")
    
    # Show clear button if documents exist
    if st.session_state.generated_docs:
        if st.button("🗑️ Clear All Documents", help="Remove all generated documents to start fresh"):
            st.session_state.generated_docs = []
            st.rerun()
    
    col1, col2, col3, col4 = st.columns(4)
    
    with col1:
        gen_stripe = st.checkbox("Stripe Compliance Brief", value=True, help="Technical brief for Stripe onboarding")
    
    with col2:
        gen_privacy = st.checkbox("Privacy Policy", value=True, help="COPPA/GDPR compliant policy")
    
    with col3:
        gen_terms = st.checkbox("Terms of Service", value=True, help="User agreement terms")
    
    with col4:
        gen_safety = st.checkbox("Parent Safety Guide", value=True, help="Safety one-pager for parents")
    
    # Generate button
    if st.button("🚀 Generate Legal Documents", type="primary", use_container_width=True):
        if not app_name:
            st.warning("⚠️ Please enter an application name.")
        else:
            with st.spinner("Generating compliance documents..."):
                try:
                    # Run Sentinel check first (for Stripe brief)
                    sentinel_status = "✓ All Artifacts Verified - Integrity Valid"
                    try:
                        sentinel = NovyxSentinel(root_dir=MEMORY_DIR, verbose=False)
                        artifacts = list(MEMORY_DIR.rglob("*.jsonld"))
                        if artifacts:
                            # Quick validation
                            passed = 0
                            for artifact_path in artifacts:
                                data, errors = sentinel.load_jsonld(artifact_path)
                                if not errors:
                                    passed += 1
                            sentinel_status = f"✓ All Artifacts Verified - Integrity Valid ({passed}/{len(artifacts)} passed)"
                    except (FileNotFoundError, PermissionError, json.JSONDecodeError, OSError):
                        pass  # Use default status
                    
                    # Clear previous docs and generate new ones
                    st.session_state.generated_docs = []
                    
                    # Generate Stripe brief
                    if gen_stripe:
                        st.info("📄 Generating Stripe Compliance Brief...")
                        brief = generate_stripe_brief(app_name, sentinel_status)
                        st.session_state.generated_docs.append(("Stripe Compliance Brief", brief, "stripe_brief"))
                    
                    # Generate Privacy Policy
                    if gen_privacy:
                        st.info("📜 Generating Privacy Policy...")
                        policy_path = generate_privacy_policy(app_name)
                        with open(policy_path, 'r') as f:
                            policy = json.load(f)
                        st.session_state.generated_docs.append(("Privacy Policy", policy, "privacy_policy"))
                    
                    # Generate Terms of Service
                    if gen_terms:
                        st.info("📋 Generating Terms of Service...")
                        terms_path = generate_terms_of_service(app_name)
                        with open(terms_path, 'r') as f:
                            terms = json.load(f)
                        st.session_state.generated_docs.append(("Terms of Service", terms, "terms_of_service"))
                    
                    # Generate Parent Safety Guide
                    if gen_safety:
                        st.info("🛡️ Generating Parent Safety Guide...")
                        safety_path = generate_parent_safety_onepager(app_name)
                        with open(safety_path, 'r') as f:
                            safety = json.load(f)
                        st.session_state.generated_docs.append(("Parent Safety Guide", safety, "parent_safety"))
                    
                    # Success message
                    st.markdown(f"""
                    <div class="success-box">
                        <h3>✅ Legal Documents Generated Successfully!</h3>
                        <p><strong>Generated:</strong> {len(st.session_state.generated_docs)} documents</p>
                        <p><strong>Location:</strong> <code>spokes/legal_gen/artifacts/</code></p>
                        <p><strong>Timestamp:</strong> {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
                    </div>
                    """, unsafe_allow_html=True)
                    
                    st.balloons()
                
                except Exception as e:
                    st.markdown(f"""
                    <div class="error-box">
                        <h4>❌ Document Generation Failed</h4>
                        <p>{str(e)}</p>
                    </div>
                    """, unsafe_allow_html=True)
                    st.exception(e)
    
    # Display generated documents (outside the generation block so they persist)
    if st.session_state.generated_docs:
        st.markdown("---")
        st.subheader("📚 Generated Documents")
        
        for doc_name, doc_data, doc_type in st.session_state.generated_docs:
                        with st.expander(f"📄 {doc_name}", expanded=False):
                            # Document metadata
                            col1, col2 = st.columns([2, 1])
                            
                            with col1:
                                st.markdown(f"**Type:** {doc_type}")
                                if 'uuid' in doc_data:
                                    st.markdown(f"**UUID:** `{doc_data['uuid']}`")
                                if 'novyx:integrityHash' in doc_data:
                                    hash_val = doc_data['novyx:integrityHash']
                                    st.markdown(f"**Integrity Hash:** `{hash_val[:32]}...`")
                            
                            with col2:
                                # Generate human-readable HTML version
                                html_content = generate_readable_document(doc_name, doc_data, doc_type)
                                html_filename = f"{doc_type}_{datetime.now().strftime('%Y-%m-%d')}.html"
                                
                                # Download HTML button (primary)
                                st.download_button(
                                    label="📄 Download Document (HTML)",
                                    data=html_content,
                                    file_name=html_filename,
                                    mime="text/html",
                                    use_container_width=True,
                                    key=f"download_html_{doc_type}_{id(doc_data)}",
                                    help="Human-readable document you can open in browser or save as PDF"
                                )
                                
                                # Download JSON button (secondary, for technical use)
                                doc_json = json.dumps(doc_data, indent=2)
                                json_filename = f"{doc_type}_{datetime.now().strftime('%Y-%m-%d')}.json"
                                st.download_button(
                                    label="⬇️ Download JSON (Technical)",
                                    data=doc_json,
                                    file_name=json_filename,
                                    mime="application/json",
                                    use_container_width=True,
                                    key=f"download_json_{doc_type}_{id(doc_data)}",
                                    help="Machine-readable format for technical integration"
                                )
                            
                            # Editable preview
                            st.markdown("**Document Preview** (editable):")
                            edited_json = st.text_area(
                                "Edit document if needed:",
                                value=json.dumps(doc_data, indent=2),
                                height=400,
                                key=f"edit_{doc_type}",
                                label_visibility="collapsed"
                            )
                            
                            # Save edited version button
                            col1, col2 = st.columns([1, 1])
                            with col1:
                                if st.button(f"💾 Save Edited Version", key=f"save_{doc_type}_{id(doc_data)}"):
                                    try:
                                        edited_data = json.loads(edited_json)
                                        save_dir = Path("spokes/legal_gen/artifacts")
                                        save_dir.mkdir(parents=True, exist_ok=True)
                                        save_path = save_dir / f"{doc_type}_edited_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.json"
                                        with open(save_path, 'w') as f:
                                            json.dump(edited_data, f, indent=2)
                                        st.success(f"✅ Saved to: `{save_path}`")
                                    except json.JSONDecodeError as e:
                                        st.error(f"❌ Invalid JSON: {e}")
                                    except Exception as e:
                                        st.error(f"❌ Save failed: {e}")
                            
                            with col2:
                                if st.button(f"📋 Copy to Clipboard", key=f"copy_{doc_type}_{id(doc_data)}"):
                                    st.code(edited_json, language="json")
                            
                            # Key highlights (if Stripe brief)
                            if doc_type == "stripe_brief":
                                st.markdown("**🔑 Key Compliance Assertions:**")
                                if 'coppa_compliance' in doc_data:
                                    st.markdown("- ✅ COPPA: Parental consent required")
                                    st.markdown(f"- ✅ Data Minimization: {len(doc_data['coppa_compliance']['data_collected'])} fields collected")
                                if 'gdpr_compliance' in doc_data:
                                    st.markdown("- ✅ GDPR: Right to access, erasure, portability")
                                if 'payment_processing' in doc_data:
                                    st.markdown(f"- ✅ Payment: {doc_data['payment_processing']['processor']} (PCI compliant)")
                            
                            # Shareable content (if safety guide)
                            if doc_type == "parent_safety" and 'one_pager_content' in doc_data:
                                st.markdown("**📱 Shareable Social Media Posts:**")
                                shareable = doc_data['one_pager_content'].get('ShareableFormat', {})
                                if 'Facebook_Post' in shareable:
                                    st.text_area(
                                        "Facebook Post:",
                                        value=shareable['Facebook_Post'],
                                        height=100,
                                        key=f"fb_{doc_type}"
                                    )
                                if 'Instagram_Caption' in shareable:
                                    st.text_area(
                                        "Instagram Caption:",
                                        value=shareable['Instagram_Caption'],
                                        height=80,
                                        key=f"ig_{doc_type}_{id(doc_data)}"
                                    )
        
        # Next steps (only show if documents exist)
        st.markdown("---")
        st.subheader("🎯 Next Steps")
        
        col1, col2 = st.columns(2)
        
        with col1:
            st.markdown("""
            **For Stripe Onboarding:**
            1. Download Stripe Compliance Brief
            2. Upload to Stripe support ticket
            3. Reference Novyx Sentinel verification
            4. Provide public verification link
            """)
        
        with col2:
            st.markdown("""
            **For Legal Counsel:**
            1. Share artifacts directory with counsel
            2. Counsel can verify integrity hashes
            3. Update assertions based on feedback
            4. Re-generate with updated details
            """)


def main():
    """Main dashboard application."""
    render_header()
    
    # Render sidebar and get selected page
    page = render_sidebar()
    
    # Render selected page
    if page == "📊 Overview":
        render_overview()
    elif page == "📥 Ingest":
        render_ingest()
    elif page == "🔍 Search":
        render_search()
    elif page == "🛡️ Integrity":
        render_integrity()
    elif page == "📚 Browse":
        render_browse()
    elif page == "🧭 Decisions":
        render_decisions()
    elif page == "⚖️ Legal":
        render_legal()


if __name__ == "__main__":
    main()
