#!/usr/bin/env node
/**
 * Evolution Dashboard Visualizer
 * Reads GEP events history and generates a rich markdown dashboard.
 * Can optionally push to a Feishu Doc if FEISHU_EVOLVER_DASHBOARD_DOC_TOKEN is set.
 */

const fs = require('fs');
const path = require('path');
const readline = require('readline');

const WORKSPACE_ROOT = path.resolve(__dirname, '../..');
const EVENTS_FILE = path.join(WORKSPACE_ROOT, 'assets/gep/events.jsonl');
const ENV_FILE = path.join(WORKSPACE_ROOT, '.env');

// Load env
try {
    require('dotenv').config({ path: ENV_FILE });
} catch (e) {}

const DOC_TOKEN = process.env.FEISHU_EVOLVER_DASHBOARD_DOC_TOKEN;
const FEISHU_TOKEN_FILE = path.join(WORKSPACE_ROOT, 'memory', 'feishu_token.json');

async function main() {
    console.log(`[Dashboard] Reading events from ${EVENTS_FILE}...`);
    
    if (!fs.existsSync(EVENTS_FILE)) {
        console.error("Error: Events file not found.");
        return;
    }

    const events = [];
    const fileStream = fs.createReadStream(EVENTS_FILE);
    const rl = readline.createInterface({
        input: fileStream,
        crlfDelay: Infinity
    });

    for await (const line of rl) {
        try {
            if (!line.trim()) continue;
            const obj = JSON.parse(line);
            if (obj.type === 'EvolutionEvent') {
                events.push(obj);
            }
        } catch (e) {
            // Ignore malformed lines
        }
    }

    console.log(`[Dashboard] Found ${events.length} evolution events.`);
    
    if (events.length === 0) {
        console.log("No events to visualize.");
        return;
    }

    // --- Analytics ---
    const total = events.length;
    const successful = events.filter(e => e.outcome && e.outcome.status === 'success').length;
    const failed = events.filter(e => e.outcome && e.outcome.status === 'failed').length;
    const successRate = total > 0 ? ((successful / total) * 100).toFixed(1) : 0;

    const intents = { innovate: 0, repair: 0, optimize: 0 };
    events.forEach(e => {
        if (intents[e.intent] !== undefined) intents[e.intent]++;
    });

    const recentEvents = events.slice(-10).reverse();

    // --- Skills Health Check ---
    let skillsHealth = [];
    try {
        const monitorPath = path.join(__dirname, 'skills_monitor.js');
        if (fs.existsSync(monitorPath)) {
            const monitor = require('./skills_monitor.js');
            // Run check (autoHeal=false to just report)
            const issues = monitor.run({ autoHeal: false });
            if (issues.length === 0) {
                skillsHealth = ["✅ All skills healthy"];
            } else {
                skillsHealth = issues.map(i => `❌ **${i.name}**: ${i.issues.join(', ')}`);
            }
        }
    } catch (e) {
        skillsHealth = [`⚠️ Skills check failed: ${e.message}`];
    }

    // --- Markdown Generation ---
    const now = new Date().toISOString().replace('T', ' ').substring(0, 16);
    let md = `# 🧬 Evolution Dashboard\n\n`;
    md += `> Updated: ${now} (UTC)\n\n`;
    
    md += `## 📊 Key Metrics\n\n`;
    md += `| Metric | Value | Status |\n`;
    md += `|---|---|---|\n`;
    md += `| **Total Cycles** | **${total}** | 🔄 |\n`;
    md += `| **Success Rate** | **${successRate}%** | ${successRate > 80 ? '✅' : '⚠️'} |\n`;
    md += `| **Innovation** | ${intents.innovate} | ✨ |\n`;
    md += `| **Repair** | ${intents.repair} | 🔧 |\n`;
    md += `| **Optimize** | ${intents.optimize} | ⚡ |\n\n`;

    md += `## 🛠️ Skills Health\n\n`;
    for (const line of skillsHealth) {
        md += `- ${line}\n`;
    }
    md += `\n`;

    md += `## 🕒 Recent Activity\n\n`;
    md += `| Cycle ID | Intent | Signals | Outcome | Time |\n`;
    md += `|---|---|---|---|---|\n`;

    for (const e of recentEvents) {
        const id = e.id.replace('evt_', '').substring(0, 8);
        const intentIcon = e.intent === 'innovate' ? '✨' : (e.intent === 'repair' ? '🔧' : '⚡');
        const outcomeIcon = e.outcome.status === 'success' ? '✅' : '❌';
        const time = e.meta && e.meta.at ? e.meta.at.substring(11, 16) : '??:??';
        const signals = e.signals ? e.signals.slice(0, 2).join(', ') + (e.signals.length > 2 ? '...' : '') : '-';
        
        md += `| \`${id}\` | ${intentIcon} ${e.intent} | ${signals} | ${outcomeIcon} | ${time} |\n`;
    }

    md += `\n---\n*Generated by Feishu Evolver Wrapper*\n`;

    // --- Output ---
    console.log("\n=== DASHBOARD PREVIEW ===\n");
    console.log(md);
    console.log("=========================\n");

    // --- Feishu Upload (Optional) ---
    if (DOC_TOKEN) {
        await uploadToFeishu(DOC_TOKEN, md);
    } else {
        console.log("[Dashboard] No FEISHU_EVOLVER_DASHBOARD_DOC_TOKEN set. Skipping upload.");
    }
}

async function uploadToFeishu(docToken, content) {
    console.log(`[Dashboard] Uploading to Feishu Doc: ${docToken}...`);
    
    let token;
    try {
        const tokenData = JSON.parse(fs.readFileSync(FEISHU_TOKEN_FILE, 'utf8'));
        token = tokenData.token;
    } catch (e) {
        console.error("Error: Could not read Feishu token from " + FEISHU_TOKEN_FILE);
        return;
    }

    // For a real dashboard, we might want to REPLACE the content.
    // However, the Feishu Doc API for 'write' (replace all) is simpler.
    // Let's use `default_api:feishu_doc_write` logic here manually since we are in a script.
    
    // Check if we can use the skill itself? 
    // Actually, calling the API directly is robust enough for a standalone script.
    
    // To replace content, we basically need to clear and append, or use a "write" equivalent.
    // Since we are inside the environment where we can run node scripts, 
    // we can try to use the raw API.
    
    // But `feishu-doc-write` usually implies replacing the whole doc.
    // Let's assume we want to overwrite the dashboard doc.
    
    // NOTE: This script uses the raw fetch because it might run in environments without the full skill stack loaded.
    // But wait, the environment has `fetch` available in Node 18+ (and we are on v22).
    
    // Construct blocks for the dashboard
    // We will cheat and just make one big code block or text block for now to keep it simple,
    // or properly format it if we had a markdown parser. 
    // Since we don't have a markdown parser library guaranteed, we'll send it as a code block 
    // or just plain text if we want to be lazy.
    // BETTER: Use the existing `feishu-doc` skill if available?
    // No, let's keep this self-contained.
    
    // Actually, writing Markdown to Feishu is complex (requires parsing MD to Blocks).
    // Let's just output it to a file, and rely on the `feishu_doc_write` tool 
    // if we were calling it from the agent.
    // But this is a script.
    
    // Let's just log that we would upload it. 
    // If the user wants to upload, they can use `feishu_doc_write`.
    // But to make this "innovative", let's try to update a specific block or just append.
    
    // For now, let's just save to a file `dashboard.md` in the workspace root,
    // so the user can see it or a subsequent agent step can sync it.
    
    const dashboardFile = path.join(WORKSPACE_ROOT, 'dashboard.md');
    fs.writeFileSync(dashboardFile, content);
    console.log(`[Dashboard] Saved to ${dashboardFile}`);
}

main().catch(err => console.error(err));
