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';

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";

let currentWatcher = null;
let syncTimeout = null;
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);
        }
    });
}

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

    const corsOptionsDelegate = (req, callback) => {
        const origin = req.header('Origin');
        const allowedWebApps = ['https://thrust.web.app', 'http://localhost:3000']; 
        if (req.path.startsWith('/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, '..', 'frontend');

    app.post('/MCP', (req, res) => {
        const { method } = req.body;
        broadcastLocalLog('system', `🤖 [MCP] Call intercepted: ${method}`);
        res.json({ success: true, message: "MCP Endpoint Active" });
    });

    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.post('/api/auth/callback', async (req, res) => {
        // --- NEW: Capture email from payload ---
        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();
                // --- NEW: Save email to config ---
                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; }

        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);
        syncContext(folderPath); 
        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;
            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);
            syncContext(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) {}
}

async function startWatching(projectPath) {
    try {
        if (currentWatcher) await currentWatcher.close();
        broadcastLocalLog('system', `👁️ Started watching: ${projectPath}`);
        
        currentWatcher = chokidar.watch(projectPath, {
            ignored: [/(^|[\/\\])\../, '**/node_modules/**'],
            persistent: true,
            ignoreInitial: true
        });

        currentWatcher.on('all', (event, filePath) => {
            const relativePath = path.relative(projectPath, filePath);
            broadcastLocalLog('watch', `[${event.toUpperCase()}] ${relativePath}`);
            clearTimeout(syncTimeout);
            syncTimeout = setTimeout(() => syncContext(projectPath), 3000);
        });
    } catch (err) {}
}

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; 
            const activeProj = getActiveProject();
            if (activeProj) syncContext(activeProj.path);
        });
        
        globalWs.on('message', (data) => {
            try {
                const msg = JSON.parse(data.toString());
                if (msg.type === 'toast' || msg.type === 'response') {
                    broadcastLocalLog('ai', `🔔 [AI]: ${msg.message || msg.text}`);
                }
                if (msg.type === 'status') broadcastLocalLog('system', `🤖 AI Status: ${msg.status}...`);
            } 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) return;
    try {
        const git = simpleGit(projectPath);
        const isRepo = await git.checkIsRepo().catch(() => false);
        if (!isRepo) return;

        const status = await git.status();
        const diff = await git.diff();
        
        globalWs.send(JSON.stringify({ type: "context_sync", data: { files_changed: status.modified, diffs: diff } }));
        broadcastLocalLog('sync', `✅ Git state diff synced to AI.`);
    } catch (e) {}
}
