#!/usr/bin/env node
import { randomUUID as T } from "node:crypto";
import { StreamableHTTPServerTransport as f } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { isInitializeRequest as h } from "@modelcontextprotocol/sdk/types.js";
import S from "dotenv";
import m from "express";
import { g as v } from "./mcp-server-BxuJ84xm.js";
S.config();
const d = Number.parseInt(process.env.PORT || "3000", 10), l = Number.parseInt(process.env.SESSION_TIMEOUT_MS || "1800000", 10), t = /* @__PURE__ */ new Map();
function u(i) {
  const r = t.get(i);
  r && (clearTimeout(r.timeoutId), r.transport.close(), t.delete(i), console.error(`[Session] Cleaned up session ${i} due to inactivity`));
}
function p(i) {
  const r = t.get(i);
  r && (clearTimeout(r.timeoutId), r.lastActivity = Date.now(), r.timeoutId = setTimeout(() => u(i), l));
}
function g() {
  const i = process.env.TODOIST_BASE_URL, r = process.env.TODOIST_API_KEY;
  r || (console.error("Error: TODOIST_API_KEY environment variable is required"), process.exit(1));
  const a = m();
  a.use(m.json()), a.get("/health", (o, n) => {
    n.json({
      status: "ok",
      activeSessions: t.size,
      sessionTimeoutMs: l
    });
  }), a.post("/mcp", async (o, n) => {
    const s = o.headers["mcp-session-id"];
    try {
      if (s && t.has(s)) {
        const e = t.get(s);
        e && (p(s), await e.transport.handleRequest(o, n, o.body));
      } else if (!s && h(o.body)) {
        const e = new f({
          sessionIdGenerator: () => T(),
          onsessioninitialized: (c) => {
            const I = setTimeout(() => u(c), l);
            t.set(c, {
              transport: e,
              lastActivity: Date.now(),
              timeoutId: I
            }), console.error(`[Session] New session initialized: ${c}`);
          }
        });
        e.onclose = () => {
          if (e.sessionId) {
            const c = t.get(e.sessionId);
            c && (clearTimeout(c.timeoutId), t.delete(e.sessionId), console.error(`[Session] Session closed: ${e.sessionId}`));
          }
        }, await v({ todoistApiKey: r, baseUrl: i }).connect(e), await e.handleRequest(o, n, o.body);
      } else
        n.status(400).json({
          jsonrpc: "2.0",
          error: {
            code: -32001,
            message: "Invalid session. Please reconnect to establish a new session."
          },
          id: null
        });
    } catch (e) {
      console.error("[Error] Request handling failed:", e), n.status(500).json({
        jsonrpc: "2.0",
        error: {
          code: -32603,
          message: "Internal server error"
        },
        id: null
      });
    }
  }), a.get("/mcp", async (o, n) => {
    const s = o.headers["mcp-session-id"];
    if (!s || !t.has(s)) {
      n.status(400).json({
        jsonrpc: "2.0",
        error: {
          code: -32001,
          message: "Invalid or expired session. Please reconnect."
        },
        id: null
      });
      return;
    }
    const e = t.get(s);
    e && (p(s), await e.transport.handleRequest(o, n));
  }), a.delete("/mcp", async (o, n) => {
    const s = o.headers["mcp-session-id"];
    if (!s || !t.has(s)) {
      n.status(400).json({
        jsonrpc: "2.0",
        error: {
          code: -32001,
          message: "Invalid session"
        },
        id: null
      });
      return;
    }
    const e = t.get(s);
    e && await e.transport.handleRequest(o, n);
  }), a.listen(d, () => {
    console.error(`Todoist MCP HTTP Server started on port ${d}`), console.error(
      `Session timeout: ${l}ms (${l / 6e4} minutes)`
    ), console.error(`MCP endpoint: http://localhost:${d}/mcp`), console.error(`Health check: http://localhost:${d}/health`);
  });
}
g();
