#!/usr/bin/env node

/**
 * HTTP REST Adapter for Harmony MCP
 *
 * This provides a REST API that forwards requests to the Harmony API.
 * It accepts Bearer tokens (JWT) or X-API-Key headers for authentication.
 *
 * This adapter is useful for non-MCP clients that want to interact with
 * Harmony via HTTP instead of the MCP stdio protocol.
 */

import { serve } from "bun";
import { Hono } from "hono";
import { cors } from "hono/cors";
import { loadConfig } from "./config.js";

const app = new Hono();

// CORS configuration
app.use(
  "/*",
  cors({
    origin: [
      "https://gethmy.com",
      "https://app.gethmy.com",
      "http://localhost:8080",
      "http://localhost:3000",
    ],
    allowMethods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
    allowHeaders: ["Content-Type", "Authorization", "X-API-Key"],
  }),
);

// Get API URL from config or use default
function getApiUrl(): string {
  const config = loadConfig();
  return config.apiUrl;
}

// Forward request to Harmony API
async function forwardToApi(
  method: string,
  path: string,
  authHeader: string | undefined,
  apiKey: string | undefined,
  body?: unknown,
): Promise<{ data: unknown; status: number }> {
  const apiUrl = getApiUrl();

  const headers: Record<string, string> = {
    "Content-Type": "application/json",
  };

  // Use API key if provided, otherwise forward the Authorization header
  if (apiKey) {
    headers["X-API-Key"] = apiKey;
  } else if (authHeader) {
    headers.Authorization = authHeader;
  } else {
    throw new Error("Unauthorized: Missing API key or Authorization header");
  }

  const response = await fetch(`${apiUrl}${path}`, {
    method,
    headers,
    body: body ? JSON.stringify(body) : undefined,
  });

  const data = await response.json();
  return { data, status: response.status };
}

// Health check
app.get("/health", (c) =>
  c.json({ status: "ok", service: "harmony-mcp-http" }),
);

// List available endpoints
app.get("/", (c) =>
  c.json({
    service: "Harmony MCP HTTP Adapter",
    endpoints: {
      workspaces: {
        list: "GET /workspaces",
        members: "GET /workspaces/:id/members",
        projects: "GET /workspaces/:id/projects",
      },
      board: {
        get: "GET /board/:projectId",
      },
      cards: {
        create: "POST /cards",
        get: "GET /cards/:id",
        getByShortId: "GET /projects/:projectId/cards/:shortId",
        update: "PATCH /cards/:id",
        delete: "DELETE /cards/:id",
        move: "POST /cards/:id/move",
        search: "GET /search?q=query",
      },
      columns: {
        create: "POST /columns",
        update: "PATCH /columns/:id",
        delete: "DELETE /columns/:id",
      },
      labels: {
        create: "POST /labels",
        addToCard: "POST /cards/:id/labels",
        removeFromCard: "DELETE /cards/:id/labels/:labelId",
      },
      subtasks: {
        create: "POST /subtasks",
        toggle: "POST /subtasks/:id/toggle",
        delete: "DELETE /subtasks/:id",
      },
      nlu: {
        process: "POST /nlu",
      },
    },
    authentication: "Include X-API-Key header or Authorization: Bearer <token>",
  }),
);

// Generic proxy handler
async function handleRequest(
  c: {
    req: {
      method: string;
      url: string;
      header: (name: string) => string | undefined;
    };
    json: () => Promise<unknown>;
  },
  method: string,
  path: string,
) {
  try {
    const authHeader = c.req.header("Authorization");
    const apiKey = c.req.header("X-API-Key");

    let body: unknown;
    if (["POST", "PATCH", "PUT"].includes(method)) {
      try {
        body = await c.json();
      } catch {
        // No body or invalid JSON
      }
    }

    const { data, status } = await forwardToApi(
      method,
      path,
      authHeader,
      apiKey,
      body,
    );
    return new Response(JSON.stringify(data), {
      status,
      headers: { "Content-Type": "application/json" },
    });
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    const status = message.includes("Unauthorized") ? 401 : 500;
    return new Response(JSON.stringify({ error: message }), {
      status,
      headers: { "Content-Type": "application/json" },
    });
  }
}

// Workspaces
app.get("/workspaces", (c) => handleRequest(c, "GET", "/workspaces"));
app.get("/workspaces/:id/members", (c) =>
  handleRequest(c, "GET", `/workspaces/${c.req.param("id")}/members`),
);
app.get("/workspaces/:id/projects", (c) =>
  handleRequest(c, "GET", `/workspaces/${c.req.param("id")}/projects`),
);

// Projects
app.get("/projects", (c) => {
  const workspaceId = new URL(c.req.url).searchParams.get("workspace_id");
  return handleRequest(c, "GET", `/projects?workspace_id=${workspaceId}`);
});

// Get card by short ID: GET /projects/:projectId/cards/:shortId
app.get("/projects/:projectId/cards/:shortId", (c) =>
  handleRequest(
    c,
    "GET",
    `/projects/${c.req.param("projectId")}/cards/${c.req.param("shortId")}`,
  ),
);

// Board
app.get("/board/:projectId", (c) =>
  handleRequest(c, "GET", `/board/${c.req.param("projectId")}`),
);

// Cards
app.get("/cards/:id", (c) =>
  handleRequest(c, "GET", `/cards/${c.req.param("id")}`),
);
app.post("/cards", (c) => handleRequest(c, "POST", "/cards"));
app.patch("/cards/:id", (c) =>
  handleRequest(c, "PATCH", `/cards/${c.req.param("id")}`),
);
app.delete("/cards/:id", (c) =>
  handleRequest(c, "DELETE", `/cards/${c.req.param("id")}`),
);
app.post("/cards/:id/move", (c) =>
  handleRequest(c, "POST", `/cards/${c.req.param("id")}/move`),
);
app.post("/cards/:id/labels", (c) =>
  handleRequest(c, "POST", `/cards/${c.req.param("id")}/labels`),
);
app.delete("/cards/:id/labels/:labelId", (c) =>
  handleRequest(
    c,
    "DELETE",
    `/cards/${c.req.param("id")}/labels/${c.req.param("labelId")}`,
  ),
);

// Search
app.get("/search", (c) => {
  const params = new URL(c.req.url).searchParams;
  return handleRequest(c, "GET", `/search?${params.toString()}`);
});

// Columns
app.post("/columns", (c) => handleRequest(c, "POST", "/columns"));
app.patch("/columns/:id", (c) =>
  handleRequest(c, "PATCH", `/columns/${c.req.param("id")}`),
);
app.delete("/columns/:id", (c) =>
  handleRequest(c, "DELETE", `/columns/${c.req.param("id")}`),
);

// Labels
app.post("/labels", (c) => handleRequest(c, "POST", "/labels"));

// Subtasks
app.post("/subtasks", (c) => handleRequest(c, "POST", "/subtasks"));
app.post("/subtasks/:id/toggle", (c) =>
  handleRequest(c, "POST", `/subtasks/${c.req.param("id")}/toggle`),
);
app.delete("/subtasks/:id", (c) =>
  handleRequest(c, "DELETE", `/subtasks/${c.req.param("id")}`),
);

// NLU
app.post("/nlu", (c) => handleRequest(c, "POST", "/nlu"));
app.post("/nlu/process", (c) => handleRequest(c, "POST", "/nlu"));

// Start server
const port = parseInt(process.env.PORT || "3001", 10);

console.log(`Starting Harmony MCP HTTP adapter on port ${port}...`);

serve({
  fetch: app.fetch,
  port,
});

console.log(`Harmony MCP HTTP adapter running at http://localhost:${port}`);
