import fs from "node:fs";
import http from "node:http";
import path from "node:path";
import { getConfigDir, getProfile } from "../config/index.js";
import { getCurrentVersion } from "../utils/version-check.js";
import { logger } from "../logger.js";
import { getAgentState } from "../agent/state.js";
import { loadMailbox, setActiveSession } from "../agent/mailbox.js";
import { generateToken } from "../obs/token.js";
import { scheduleRestart } from "../utils/restart.js";
export const TUI_PORT_FILE = "tui-port";
function json(res, status, data) {
    res.statusCode = status;
    res.setHeader("content-type", "application/json; charset=utf-8");
    res.setHeader("cache-control", "no-store");
    res.end(JSON.stringify(data));
}
function readBody(req) {
    return new Promise((resolve, reject) => {
        let body = "";
        let size = 0;
        req.on("data", (chunk) => {
            size += chunk.length;
            if (size > 65536) {
                reject(new Error("Body too large"));
                req.destroy();
                return;
            }
            body += chunk.toString();
        });
        req.on("end", () => resolve(body));
        req.on("error", reject);
    });
}
export function startTuiServer(options = {}) {
    const envPort = process.env.TUI_PORT ? parseInt(process.env.TUI_PORT, 10) : undefined;
    const requestedPort = envPort && Number.isFinite(envPort) ? envPort : 0;
    const logBuffer = [];
    const maxLogBuffer = 200;
    const unsubscribe = logger.onLog((entry) => {
        if (entry.category !== "screenshot") {
            logBuffer.push(entry);
            if (logBuffer.length > maxLogBuffer)
                logBuffer.shift();
        }
    });
    const server = http.createServer((req, res) => {
        try {
            handleRequest(req, res);
        }
        catch (err) {
            logger.warn(`[tui-server] Unhandled error: ${err instanceof Error ? err.message : String(err)}`);
            if (!res.headersSent) {
                res.statusCode = 500;
                res.end("Internal Server Error");
            }
        }
    });
    function handleRequest(req, res) {
        const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
        const pathname = url.pathname;
        if (pathname === "/tui/status") {
            try {
                const state = getAgentState();
                const mb = loadMailbox();
                json(res, 200, {
                    agentName: options.config?.agentName ?? "VisionClaw",
                    version: getCurrentVersion(),
                    profile: getProfile(),
                    busy: state.busy,
                    stopRequested: state.stopRequested,
                    compacting: state.compacting,
                    activeSession: mb.activeSession,
                    codingSession: mb.codingSession,
                    queueSize: state.messageQueue.size(),
                    uptime: Math.floor(process.uptime()),
                    channels: state.channelManager.getEnabledChannels(),
                    pid: process.pid,
                });
            }
            catch (err) {
                json(res, 500, { error: err instanceof Error ? err.message : String(err) });
            }
            return;
        }
        if (pathname === "/tui/events") {
            try {
                const senderId = url.searchParams.get("sender") ?? `tui-anon-${Date.now()}`;
                const state = getAgentState();
                const tui = state.channelManager.getAdapter("tui");
                if (!tui) {
                    json(res, 503, { error: "TUI adapter not available" });
                    return;
                }
                tui.addSseClient(res, senderId);
            }
            catch (err) {
                json(res, 500, { error: err instanceof Error ? err.message : String(err) });
            }
            return;
        }
        if (pathname === "/tui/send" && req.method === "POST") {
            void (async () => {
                try {
                    const body = await readBody(req);
                    const state = getAgentState();
                    const parsed = JSON.parse(body);
                    if (!parsed.text || typeof parsed.text !== "string") {
                        json(res, 400, { error: "Missing 'text' field" });
                        return;
                    }
                    const sender = parsed.sender ?? `tui-${process.pid}`;
                    const msg = {
                        id: `tui-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
                        channel: "tui",
                        sender,
                        text: parsed.text,
                        attachments: [],
                        timestamp: new Date().toISOString(),
                        meta: { source: "tui" },
                    };
                    state.replyMap.set(`tui::${sender}`, {
                        sender,
                        channel: "tui",
                        replyContext: { messageId: msg.id },
                    });
                    const tui = state.channelManager.getAdapter("tui");
                    if (tui) {
                        tui.injectMessage(msg);
                        tui.pushEvent({
                            type: "ack",
                            timestamp: new Date().toISOString(),
                            commandId: msg.id,
                            commandState: "queued",
                        }, sender);
                    }
                    else {
                        state.messageQueue.enqueue(msg);
                        state.channelManager.emit("message", msg);
                    }
                    json(res, 200, { ok: true, messageId: msg.id });
                }
                catch (err) {
                    json(res, 500, { error: err instanceof Error ? err.message : String(err) });
                }
            })();
            return;
        }
        if (pathname === "/tui/logs") {
            json(res, 200, logBuffer.slice(-100));
            return;
        }
        // ── Dedicated slash command endpoints (bypass agent loop) ──────────
        if (pathname === "/tui/restart" && req.method === "POST") {
            try {
                scheduleRestart(3000);
                json(res, 200, { ok: true, message: "Restart scheduled in 3 seconds" });
            }
            catch (err) {
                json(res, 500, { error: err instanceof Error ? err.message : String(err) });
            }
            return;
        }
        if (pathname === "/tui/upgrade" && req.method === "POST") {
            void (async () => {
                try {
                    const body = await readBody(req);
                    const parsed = JSON.parse(body);
                    const tag = parsed.tag ?? "latest";
                    const { performUpgrade } = await import("../tools/upgrade.js");
                    const result = await performUpgrade({ tag });
                    json(res, 200, result);
                }
                catch (err) {
                    json(res, 500, { error: err instanceof Error ? err.message : String(err) });
                }
            })();
            return;
        }
        if (pathname === "/tui/rdp" && req.method === "POST") {
            void (async () => {
                try {
                    const body = await readBody(req);
                    const parsed = JSON.parse(body);
                    const ttl = Math.max(5, Math.min(480, parsed.ttlMinutes ?? 30));
                    const reason = (parsed.reason ?? "TUI remote desktop request").slice(0, 200);
                    const { token, expiresAt } = generateToken(ttl, reason);
                    const baseUrl = (getAgentState().consoleUrl ?? "")
                        .replace(/\/(obs|console)(\/.*)?$/, "")
                        .replace(/\/$/, "");
                    if (!baseUrl) {
                        json(res, 503, { error: "Tunnel URL unavailable — remote desktop requires an active tunnel" });
                        return;
                    }
                    json(res, 200, { url: `${baseUrl}/rdp/${token}`, expiresAt, ttlMinutes: ttl });
                }
                catch (err) {
                    json(res, 500, { error: err instanceof Error ? err.message : String(err) });
                }
            })();
            return;
        }
        if (pathname === "/tui/switch" && req.method === "POST") {
            void (async () => {
                try {
                    const body = await readBody(req);
                    const parsed = JSON.parse(body);
                    const target = parsed.target.toLowerCase();
                    if (target !== "general" && target !== "coding") {
                        json(res, 400, { error: "target must be 'general' or 'coding'" });
                        return;
                    }
                    setActiveSession(target);
                    json(res, 200, { ok: true, activeSession: target });
                }
                catch (err) {
                    json(res, 500, { error: err instanceof Error ? err.message : String(err) });
                }
            })();
            return;
        }
        if (pathname === "/tui/wake" && req.method === "POST") {
            try {
                const state = getAgentState();
                const msg = {
                    id: `tui-wake-${Date.now()}`,
                    channel: "tui",
                    sender: "tui-system",
                    text: "wake",
                    attachments: [],
                    timestamp: new Date().toISOString(),
                    meta: { source: "tui", kind: "wake" },
                };
                state.messageQueue.enqueue(msg);
                state.channelManager.emit("message", msg);
                json(res, 200, { ok: true, message: "Wake signal sent" });
            }
            catch (err) {
                json(res, 500, { error: err instanceof Error ? err.message : String(err) });
            }
            return;
        }
        res.statusCode = 404;
        res.setHeader("content-type", "text/plain; charset=utf-8");
        res.end("Not found");
    }
    let boundPort = 0;
    server.listen(requestedPort, "127.0.0.1", () => {
        const address = server.address();
        boundPort = typeof address === "object" && address ? address.port : requestedPort;
        try {
            const portFile = path.join(getConfigDir(), TUI_PORT_FILE);
            fs.writeFileSync(portFile, String(boundPort), "utf-8");
        }
        catch (err) {
            logger.warn(`[tui-server] Failed to write port file: ${err instanceof Error ? err.message : String(err)}`);
        }
        logger.system(`TUI server: http://127.0.0.1:${boundPort}/tui (localhost only)`);
    });
    server.on("error", (err) => {
        logger.warn(`[tui-server] Failed to start: ${err instanceof Error ? err.message : String(err)}`);
    });
    return {
        get port() { return boundPort; },
        close: async () => {
            unsubscribe();
            try {
                const portFile = path.join(getConfigDir(), TUI_PORT_FILE);
                if (fs.existsSync(portFile))
                    fs.unlinkSync(portFile);
            }
            catch { /* ignore */ }
            await new Promise((resolve) => {
                server.close(() => resolve());
            });
        },
    };
}
//# sourceMappingURL=server.js.map