import { WebSocket, WebSocketServer } from 'ws';
import chokidar from 'chokidar';
import simpleGit from 'simple-git';
import express from 'express';
import open from 'open';
import path from 'path';
import net from 'net';
import fs from 'fs';
import os from 'os';
import cors from 'cors';
import { exec } from 'child_process';
import { fileURLToPath } from 'url';
import { getActiveProject, getConfig, saveConfig } from './config.js';
import { attachExternalBridges } from '../mcps/ExternalBridge.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const GATEWAY_URL = process.env.FRONT_URL || "wss://everydaycats-thrust-front-server.hf.space";
const API_URL = GATEWAY_URL.replace('ws://', 'http://').replace('wss://', 'https://');
const AUTH_PROXY_URL = "https://everydaycats-thrust-auth-server.hf.space";

// --- DEBOUNCE & POLLING TIMERS ---
const INACTIVITY_DELAY_MS = 15 * 1000;
const MCP_POLL_INTERVAL_MS = 18 * 1000;

let currentWatcher = null;
let inactivityTimer = null;
let mcpPollTimer = null;
let fileActivityBuffer = "";
let globalWs = null;
let localWss = null;
let wsRetryLogged = false;

const findAvailablePort = (startPort) => {
    return new Promise((resolve) => {
        const server = net.createServer();
        server.unref();
        server.on('error', () => resolve(findAvailablePort(startPort + 1)));
        server.listen(startPort, () => {
            server.close(() => resolve(startPort));
        });
    });
};

function broadcastLocalLog(type, message) {
    if (!localWss) return;
    const payload = JSON.stringify({ type, message });
    localWss.clients.forEach(client => {
        if (client.readyState === WebSocket.OPEN) {
            client.send(payload);
        }
    });
}

function isBinaryData(buffer) {
    for (let i = 0; i < Math.min(buffer.length, 512); i++) {
        if (buffer[i] === 0) return true;
    }
    return false;
}

// --- CENTRAL DEBOUNCER ---
function triggerDebouncedSync() {
    const activeProject = getActiveProject();
    if (!activeProject || !activeProject.path) return;

    if (inactivityTimer) clearTimeout(inactivityTimer);
    inactivityTimer = setTimeout(() => {
        syncContext(activeProject.path);
    }, INACTIVITY_DELAY_MS);
}

// --- EXTERNAL MCP INITIALIZATION (ON BOOT / ON CONNECT) ---
async function fetchInitialMCPContext(server) {
    try {
        const res = await fetch(server.url, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                jsonrpc: "2.0",
                method: "tools/call",
                params: { name: "get_initial_state", arguments: {} },
                id: Date.now()
            })
        });

        if (res.ok) {
            const data = await res.json();
            if (data.result && data.result.content && data.result.content.length > 0) {
                const stateText = data.result.content[0].text;

                fileActivityBuffer += `\n[${new Date().toLocaleTimeString()}][MCP BOOT STATE] Source: ${server.name} | Current Context:\n${stateText}\n`;
                broadcastLocalLog('mcp', `📥 Fetched initial project state from ${server.name}`);

                triggerDebouncedSync();
            }
        }
    } catch (e) {
        broadcastLocalLog('error', `⚠️ Failed to fetch initial state from ${server.name}. Is it running?`);
    }
}

export async function startDaemon(preferredPort) {
    const actualPort = await findAvailablePort(preferredPort);

    const app = express();

    attachExternalBridges(app);

    const corsOptionsDelegate = (req, callback) => {
        const origin = req.header('Origin');
        const allowedWebApps =['https://thrust.web.app', 'http://localhost:3000'];
        if (req.path.startsWith('/api/mcp')) {
            callback(null, { origin: true });
        } else if (req.path === '/api/auth/callback') {
            if (!origin || allowedWebApps.includes(origin) || origin === `http://localhost:${actualPort}`) {
                callback(null, { origin: true, credentials: true });
            } else {
                callback(new Error('CORS blocked auth callback'), { origin: false });
            }
        } else {
            callback(null, { origin: `http://localhost:${actualPort}` });
        }
    };

    app.use(cors(corsOptionsDelegate));
    app.use(express.json());

    const frontendPath = path.join(__dirname, '..', 'build');

    // ==========================================
    // MCP SERVER ENDPOINTS (FEED-IN PUSH)
    // ==========================================

    app.get('/api/mcp/context', async (req, res) => {
        const config = getConfig();
        const token = config.auth?.token;
        const projectId = config.activeLeadId;

        const prd = req.query.prd || 'true';
        const thrust = req.query.thrust || 'true';
        const timeline = req.query.timeline || 'true';

        if (!token || !projectId) {
            return res.status(401).json({ error: "Thrust agent not linked or authenticated." });
        }

        try {
            const response = await fetch(`${API_URL}/api/projects/${projectId}/mcp-context?prd=${prd}&thrust=${thrust}&timeline=${timeline}`, {
                headers: { 'Authorization': `Bearer ${token}` }
            });
            const data = await response.json();

            res.json({
                projectId,
                projectPath: config.leads[projectId].path,
                prd: data.prd,
                activeThrust: data.thrust,
                timeline: data.timeline
            });
            broadcastLocalLog('mcp', `🔗 [Context Sync] AI Client requested project state.`);
        } catch (e) {
            res.status(502).json({ error: "Failed to fetch context." });
        }
    });

    app.post('/api/mcp/timeline', (req, res) => {
        const { source, action_type, description, requires_code_sync } = req.body;

        if (!source || !description) {
            return res.status(400).json({ error: "Malformed MCP payload." });
        }

        broadcastLocalLog('mcp', `🔗 [${source} Pushed Event] ${action_type}: ${description}`);

        fileActivityBuffer += `\n[${new Date().toLocaleTimeString()}] [MCP EXT EVENT] Source: ${source} | Action: ${action_type} | Desc: ${description} | Needs Code Sync: ${requires_code_sync ? 'Yes' : 'No'}\n`;
        triggerDebouncedSync();

        res.json({ success: true, message: "Timeline event ingested to buffer." });
    });

    // ==========================================
    // MCP CLIENT CONFIGURATION (FEED-IN PULL)
    // ==========================================

    app.get('/api/mcp/servers', (req, res) => {
        res.json(getConfig().mcpServers ||[]);
    });

    app.post('/api/mcp/servers', (req, res) => {
        const { name, url } = req.body;
        if (!name || !url) return res.status(400).json({ error: "Missing name or url" });

        const config = getConfig();
        if (!config.mcpServers) config.mcpServers =[];
        config.mcpServers.push({ name, url, type: 'http' });
        saveConfig(config);

        pollExternalMCPServers();
        fetchInitialMCPContext({ name, url, type: 'http' });
        res.json({ success: true });
    });

    app.delete('/api/mcp/servers/:index', (req, res) => {
        const config = getConfig();
        const index = parseInt(req.params.index);
        if (config.mcpServers && config.mcpServers[index]) {
            config.mcpServers.splice(index, 1);
            saveConfig(config);
        }
        res.json({ success: true });
    });

    // ==========================================
    // EXTERNAL MCP DIRECT QUERY (AI OR MANUAL)
    // ==========================================
    app.post('/api/mcp/query', async (req, res) => {
        const { serverName, toolName, targetArg } = req.body;
        const config = getConfig();

        const server = config.mcpServers?.find(s => s.name.toLowerCase() === serverName.toLowerCase());

        if (!server) return res.status(404).json({ error: `MCP Server '${serverName}' not found.` });

        try {
            const payload = {
                jsonrpc: "2.0",
                method: "tools/call",
                params: {
                    name: toolName,
                    arguments: targetArg ? { target: targetArg } : {}
                },
                id: Date.now()
            };

            const response = await fetch(server.url, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(payload)
            });

            if (!response.ok) throw new Error("Server responded with error");

            const data = await response.json();
            const resultText = data.result?.content?.[0]?.text || "No data returned.";

            broadcastLocalLog('mcp', `⚡ Queried ${serverName} for ${toolName}.`);

            fileActivityBuffer += `\n[${new Date().toLocaleTimeString()}][MCP DIRECT QUERY RESULT] Source: ${serverName} | Tool: ${toolName} | Target: ${targetArg || 'none'} \nResult:\n${resultText}\n`;
            triggerDebouncedSync();

            res.json({ success: true, data: resultText });

        } catch (e) {
            broadcastLocalLog('error', `⚠️ Failed to query MCP server: ${serverName}`);
            res.status(500).json({ error: e.message });
        }
    });

    // ==========================================
    // CORE DASHBOARD API
    // ==========================================

    app.get('/api/status', (req, res) => {
        const config = getConfig();
        res.json({ auth: config.auth, activeProject: getActiveProject() });
    });

    app.get('/api/cloud-projects', async (req, res) => {
        const config = getConfig();
        const token = config.auth?.token;
        if (!token) return res.status(401).json({ error: "Not authenticated" });

        const page = req.query.page || 1;
        try {
            const response = await fetch(`${API_URL}/api/projects?page=${page}&limit=9`, {
                headers: { 'Authorization': `Bearer ${token}` }
            });
            const data = await response.json();
            if (!response.ok) throw new Error(data.error);
            res.json(data);
        } catch (e) {
            res.status(502).json({ error: "Failed to fetch from Gateway." });
        }
    });

    app.get('/api/thrusts/active', async (req, res) => {
        const config = getConfig();
        const token = config.auth?.token;
        const projectId = config.activeLeadId;

        if (!token || !projectId) return res.status(401).json({ error: "Not ready" });

        try {
            const response = await fetch(`${API_URL}/api/projects/${projectId}/thrusts/active`, {
                headers: { 'Authorization': `Bearer ${token}` }
            });
            const data = await response.json();
            if (!response.ok) throw new Error(data.error);
            res.json(data);
        } catch (e) {
            res.status(502).json({ error: "Failed to fetch current directive." });
        }
    });


	app.post('/api/tasks/complete', async (req, res) => {
        const { taskId, taskTitle } = req.body;
        const config = getConfig();
        const token = config.auth?.token;
        const projectId = config.activeLeadId;

        if (!token || !projectId) return res.status(401).json({ error: "Not authenticated" });

        try {
            const response = await fetch(`${API_URL}/api/projects/${projectId}/tasks/${taskId}/complete`, {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${token}`,
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ taskTitle })
            });

            const data = await response.json();
            if (!response.ok) throw new Error(data.error);

            // 👉 NEW: Force the buffer to have content so syncContext doesn't abort!
            // This tells the AI exactly what you just checked off manually.
            fileActivityBuffer += `\n[${new Date().toLocaleTimeString()}] [USER ACTION] Manually marked task as complete: "${taskTitle}"\n`;

            if (config.leads[projectId]?.path) {
                if (inactivityTimer) clearTimeout(inactivityTimer);
                syncContext(config.leads[projectId].path);
            }

            res.json(data);
        } catch (e) {
            res.status(502).json({ error: "Failed to sync task completion to cloud." });
        }
    });

    app.post('/api/auth/callback', async (req, res) => {
        const { tempKey, token, email } = req.body;
        try {
            let finalToken = token;
            if (tempKey && !token) {
                const response = await fetch(`${AUTH_PROXY_URL}/redeem`, {
                    method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ key: tempKey })
                });
                const data = await response.json();
                if (!data.token) return res.status(401).json({ error: "Invalid Key" });
                finalToken = data.token;
            }

            if (finalToken) {
                const config = getConfig();
                config.auth = { token: finalToken, email: email || "Authenticated User" };
                saveConfig(config);
                broadcastLocalLog('success', '✅ Authentication Successful!');
                connectWebSocket();
                return res.json({ success: true });
            } else {
                return res.status(400).json({ error: "No valid auth data provided" });
            }
        } catch (e) {
            res.status(502).json({ error: "Auth Processing Failed" });
        }
    });

    app.post('/api/auth/logout', async (req, res) => {
        const config = getConfig();
        const token = config.auth?.token;
        const projectId = config.activeLeadId;

        if (token && projectId) {
            fetch(`${API_URL}/nullify`, {
                method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ projectId })
            }).catch(() => {});
        }

        config.auth = { token: null, email: null };
        config.activeLeadId = null;
        saveConfig(config);

        if (globalWs) { globalWs.close(); globalWs = null; }
        if (currentWatcher) { await currentWatcher.close(); currentWatcher = null; }
        if (inactivityTimer) { clearTimeout(inactivityTimer); inactivityTimer = null; }
        if (mcpPollTimer) { clearInterval(mcpPollTimer); mcpPollTimer = null; }

        broadcastLocalLog('error', '🛑 Logged out. Session cleared.');
        res.json({ success: true });
    });

    app.get('/api/explore', (req, res) => {
        try {
            let targetPath = req.query.path || os.homedir();
            targetPath = path.resolve(targetPath);
            if (!fs.existsSync(targetPath)) return res.status(404).json({ error: "Directory not found" });

            const items = fs.readdirSync(targetPath, { withFileTypes: true });
            const directories = items.filter(item => item.isDirectory() && !item.name.startsWith('.')).map(item => item.name).sort();
            const parentPath = path.dirname(targetPath);

            res.json({ currentPath: targetPath, parentPath: targetPath === parentPath ? null : parentPath, directories: directories });
        } catch (error) { res.status(403).json({ error: "Permission denied." }); }
    });

    app.post('/api/link', async (req, res) => {
        const { leadId, folderPath } = req.body;
        if (!fs.existsSync(folderPath)) return res.status(400).json({ error: "Folder path not found." });

        const config = getConfig();
        config.leads[leadId] = { path: folderPath, linkedAt: new Date().toISOString() };
        config.activeLeadId = leadId;
        saveConfig(config);

        await startWatching(folderPath);
        triggerDebouncedSync();

        res.json({ success: true });
    });

    app.post('/api/unlink', async (req, res) => {
        const config = getConfig();
        config.activeLeadId = null;
        saveConfig(config);

        if (currentWatcher) {
            await currentWatcher.close();
            currentWatcher = null;
            if (inactivityTimer) { clearTimeout(inactivityTimer); inactivityTimer = null; }
            if (mcpPollTimer) { clearInterval(mcpPollTimer); mcpPollTimer = null; }
            broadcastLocalLog('system', '🛑 Stopped watching.');
        }
        res.json({ success: true });
    });

    if (fs.existsSync(frontendPath)) {
        app.use(express.static(frontendPath));
        app.get(/.*$/, (req, res) => res.sendFile(path.join(frontendPath, 'index.html')));
    }

    const server = app.listen(actualPort, () => {
        const url = `http://localhost:${actualPort}`;
        console.log(`\n========================================`);
        console.log(`🚀 Thrust Dashboard is live at: ${url}`);
        console.log(`========================================\n`);
        safeOpenBrowser(url);
    });

    localWss = new WebSocketServer({ server });
    localWss.on('connection', (ws) => {
        ws.send(JSON.stringify({ type: 'system', message: '🟢 Local UI Connected.' }));
        ws.on('message', (message) => {
            try {
                const data = JSON.parse(message.toString());
                if (data.type === 'frontend_prompt') {
                    if (globalWs && globalWs.readyState === WebSocket.OPEN) {
                        globalWs.send(JSON.stringify({ type: 'prompt', content: data.payload, projectId: getActiveProject()?.id }));
                        broadcastLocalLog('sync', `Prompt sent to Cloud Director...`);
                    } else {
                        broadcastLocalLog('error', `⚠️ Cannot send: Cloud Gateway is offline.`);
                    }
                }
            } catch (err) {}
        });
    });

    const config = getConfig();
    if (config.auth && config.auth.token) {
        connectWebSocket();
        const initialProject = getActiveProject();
        if (initialProject?.path) {
            startWatching(initialProject.path);
        }
    } else {
        console.log("\n⚠️ Agent is not authenticated. Awaiting connection from Web Dashboard...");
    }
}

async function safeOpenBrowser(url) {
    try {
        if (process.env.TERMUX_VERSION) exec(`termux-open-url ${url}`, () => {});
        else if (!process.env.DISPLAY && process.platform === 'linux') {}
        else { await open(url); }
    } catch (e) {}
}

// --- EXTERNAL MCP POLLING LOGIC ---
async function pollExternalMCPServers() {
    const config = getConfig();
    if (!config.mcpServers || config.mcpServers.length === 0) return;

    let hasNewData = false;

    for (const server of config.mcpServers) {
        try {
            const res = await fetch(server.url, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    jsonrpc: "2.0",
                    method: "tools/call",
                    params: { name: "get_recent_activity", arguments: {} },
                    id: Date.now()
                })
            });

            if (res.ok) {
                const data = await res.json();
                if (data.result && data.result.content && data.result.content.length > 0) {
                    const updateText = data.result.content[0].text;

                    if (updateText && updateText.trim() !== "" && updateText.trim() !== "No new activity") {
                        fileActivityBuffer += `\n[${new Date().toLocaleTimeString()}] [MCP POLL] Source: ${server.name} | Update: ${updateText}\n`;
                        broadcastLocalLog('mcp', `🔗 Pulled new data from ${server.name}`);
                        hasNewData = true;
                    }
                }
            }
        } catch (e) {
            // Silently fail to avoid spamming the logs
        }
    }

    if (hasNewData) {
        triggerDebouncedSync();
    }
}

// --- CORE FILE WATCHING LOGIC ---
async function startWatching(projectPath) {
    try {
        if (currentWatcher) await currentWatcher.close();
        broadcastLocalLog('system', `👁️ Started watching: ${projectPath}`);

        fileActivityBuffer = "";

        const config = getConfig();
        if (config.mcpServers && config.mcpServers.length > 0) {
            config.mcpServers.forEach(server => fetchInitialMCPContext(server));
        }

        if (mcpPollTimer) clearInterval(mcpPollTimer);
        mcpPollTimer = setInterval(pollExternalMCPServers, MCP_POLL_INTERVAL_MS);

        currentWatcher = chokidar.watch(projectPath, {
            ignored:[
                /(^|[\/\\])\../,
                '**/node_modules/**', '**/dist/**', '**/build/**',
                '**/Library/**', '**/Temp/**', '**/Logs/**', '**/obj/**', '**/ProjectSettings/**'
            ],
            persistent: true,
            ignoreInitial: true,
            ignorePermissionErrors: true // NEW: Ignores restricted Android/Termux subfolders safely
        });

        // NEW: FATAL ERROR HANDLER
        // Catches EACCES constraints before Node.js crashes and forces a UI unlink
        currentWatcher.on('error', async (error) => {
            const isPermissionError = error.code === 'EACCES' || error.code === 'EPERM';
            const msg = isPermissionError 
                ? `Permission Denied: Cannot watch folder. Access Denied by OS.`
                : `Watcher Error: ${error.message}`;
            
            broadcastLocalLog('error', msg);

            // Force unlink the bad folder
            const cfg = getConfig();
            cfg.activeLeadId = null;
            saveConfig(cfg);

            if (inactivityTimer) { clearTimeout(inactivityTimer); inactivityTimer = null; }
            if (mcpPollTimer) { clearInterval(mcpPollTimer); mcpPollTimer = null; }
            if (currentWatcher) {
                await currentWatcher.close().catch(() => {});
                currentWatcher = null;
            }

            // Signal the frontend to drop the user back to the setup wizard
            broadcastLocalLog('force_unlink', 'Folder access denied. Project unlinked safely.');
        });

        currentWatcher.on('all', (event, filePath) => {
            const relativePath = path.relative(projectPath, filePath);
            fileActivityBuffer += `[${new Date().toLocaleTimeString()}] ${event.toUpperCase()}: ${relativePath}\n`;
            broadcastLocalLog('watch', `[${event.toUpperCase()}] ${relativePath}`);

            triggerDebouncedSync();
        });
    } catch (err) {
        broadcastLocalLog('error', `Failed to initialize watcher: ${err.message}`);
    }
}

function connectWebSocket() {
    const config = getConfig();
    if (!config.auth || !config.auth.token) return;

    try {
        if (globalWs) globalWs.close();
        globalWs = new WebSocket(`${GATEWAY_URL}?token=${config.auth.token}`);

        globalWs.on('error', (err) => {
            if (err.code === 'ECONNREFUSED' && !wsRetryLogged) {
                wsRetryLogged = true;
            }
        });

        globalWs.on('open', () => {
            broadcastLocalLog('success', '🟢 Connected to Cloud Gateway.');
            wsRetryLogged = false;
        });

        globalWs.on('message', async (data) => {
            try {
                const msg = JSON.parse(data.toString());

                if (msg.type === 'mcp_query' && msg.payload) {
                    const { serverName, toolName, targetArg } = msg.payload;
                    const targetServer = getConfig().mcpServers?.find(s => s.name.toLowerCase() === serverName.toLowerCase());

                    if (targetServer) {
                        broadcastLocalLog('mcp', `🤖 AI requested data from ${serverName} (${toolName})...`);
                        try {
                            const response = await fetch(targetServer.url, {
                                method: 'POST', headers: { 'Content-Type': 'application/json' },
                                body: JSON.stringify({ jsonrpc: "2.0", method: "tools/call", params: { name: toolName, arguments: targetArg ? { target: targetArg } : {} }, id: Date.now() })
                            });
                            if (response.ok) {
                                const responseData = await response.json();
                                const resultText = responseData.result?.content?.[0]?.text || "No data returned.";
                                fileActivityBuffer += `\n[${new Date().toLocaleTimeString()}] [MCP AI QUERY RESULT] Source: ${serverName} | Tool: ${toolName} | Target: ${targetArg || 'none'} \nResult:\n${resultText}\n`;
                                triggerDebouncedSync();
                            }
                        } catch (e) {
                            broadcastLocalLog('error', `⚠️ AI failed to query MCP server: ${serverName}`);
                        }
                    }
                }

                if (msg.type === 'toast' || msg.type === 'response') {
                    broadcastLocalLog('ai', `🔔 [AI]: ${msg.message || msg.text}`);
                }
                if (msg.type === 'status') broadcastLocalLog('system', `🤖 AI Status: ${msg.status}...`);
                if (msg.should_reload || msg.type === 'reload_project') broadcastLocalLog('reload', `fetch_thrusts`);
            } catch (err) {}
        });

        globalWs.on('close', () => {
            if (!wsRetryLogged) {
                broadcastLocalLog('error', '🔴 Disconnected from Cloud Gateway. Retrying...');
                wsRetryLogged = true;
            }
            if (getConfig().auth?.token) setTimeout(connectWebSocket, 5000);
        });
    } catch (err) { setTimeout(connectWebSocket, 5000); }
}

async function syncContext(projectPath) {
    if (!globalWs || globalWs.readyState !== WebSocket.OPEN) {
        broadcastLocalLog('error', `⚠️ Cannot sync: Not connected to Cloud.`);
        return;
    }

    broadcastLocalLog('system', `⏳ 15s silence reached. Preparing sync...`);

    let diff = "";
    let newFilesData = "";
    let imagesData =[];

    try {
        const git = simpleGit(projectPath);
        const isRepo = await git.checkIsRepo().catch(() => false);

        if (isRepo) {
            const status = await git.status();
            diff = await git.diff();

            const binaryExts =[
                '.png', '.jpg', '.jpeg', '.webp', '.gif', '.svg', '.ico',
                '.pdf', '.zip', '.tar', '.gz', '.mp4', '.mp3', '.wav',
                '.exe', '.dll', '.so', '.dylib',
                '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.bin'
            ];

            for (const file of status.not_added) {
                const ext = path.extname(file).toLowerCase();
                const fullPath = path.join(projectPath, file);
                if (!fs.existsSync(fullPath)) continue;

                const stat = fs.statSync(fullPath);
                if (stat.isDirectory() || stat.size > 5 * 1024 * 1024) continue;

                const fileData = fs.readFileSync(fullPath);
                const isBinary = binaryExts.includes(ext) || isBinaryData(fileData);

                if (isBinary) {
                    const base64 = fileData.toString('base64');
                    const mime = ['.png','.jpg','.jpeg','.webp','.gif'].includes(ext)
                        ? `image/${ext.replace('.','')}`
                        : 'application/octet-stream';
                    imagesData.push(`data:${mime};base64,${base64}`);
                } else {
                    const content = fileData.toString('utf8');
                    newFilesData += `\n--- NEW FILE: ${file} (Scraped at ${new Date().toLocaleTimeString()}) ---\n${content.substring(0, 10000)}\n`;
                }
            }
        } else {
            broadcastLocalLog('system', `ℹ️ Folder is not a Git repo. Syncing MCP/Activity logs only.`);
        }
    } catch (e) {
        console.error("Git/Sync processing error:", e);
    }

    if (!fileActivityBuffer.trim() && !diff && !newFilesData) {
        broadcastLocalLog('system', `ℹ️ Buffer empty. Nothing to sync.`);
        return;
    }

    globalWs.send(JSON.stringify({
        type: "context_sync",
        projectId: getActiveProject().id,
        data: {
            buffer: fileActivityBuffer,
            diffs: diff,
            new_files: newFilesData,
            images: imagesData
        }
    }));

    broadcastLocalLog('sync', `✅ Context Batch synced to AI.`);
    fileActivityBuffer = "";
}
