#!/usr/bin/env node
import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import express from "express";
import crypto from "crypto";
import { LinearSyncService } from "./sync-service.js";
import { logger } from "../../core/monitoring/logger.js";
import chalk from "chalk";
function getEnv(key, defaultValue) {
  const value = process.env[key];
  if (value === void 0) {
    if (defaultValue !== void 0) return defaultValue;
    throw new Error(`Environment variable ${key} is required`);
  }
  return value;
}
function getOptionalEnv(key) {
  return process.env[key];
}
class LinearWebhookServer {
  app;
  server = null;
  // Using singleton logger from monitoring
  syncService;
  config;
  eventQueue = [];
  isProcessing = false;
  constructor(config) {
    this.app = express();
    this.syncService = new LinearSyncService();
    this.config = {
      port: config?.port || parseInt(process.env["WEBHOOK_PORT"] || "3456"),
      host: config?.host || process.env["WEBHOOK_HOST"] || "localhost",
      webhookSecret: config?.webhookSecret || process.env["LINEAR_WEBHOOK_SECRET"],
      maxPayloadSize: config?.maxPayloadSize || "10mb",
      rateLimit: {
        windowMs: config?.rateLimit?.windowMs || 6e4,
        max: config?.rateLimit?.max || 100
      }
    };
    this.setupMiddleware();
    this.setupRoutes();
  }
  setupMiddleware() {
    this.app.use(
      express.raw({
        type: "application/json",
        limit: this.config.maxPayloadSize
      })
    );
    this.app.use((req, res, next) => {
      res.setHeader("X-Powered-By", "StackMemory");
      next();
    });
  }
  setupRoutes() {
    this.app.get("/health", (req, res) => {
      res.json({
        status: "healthy",
        service: "linear-webhook",
        timestamp: (/* @__PURE__ */ new Date()).toISOString(),
        queue: this.eventQueue.length,
        processing: this.isProcessing
      });
    });
    this.app.post("/webhook/linear", async (req, res) => {
      try {
        if (!this.verifyWebhookSignature(req)) {
          logger.warn("Invalid webhook signature");
          return res.status(401).json({ error: "Unauthorized" });
        }
        const payload = JSON.parse(req.body.toString());
        logger.info(
          `Received webhook: ${payload.type} - ${payload.action}`
        );
        this.eventQueue.push(payload);
        this.processQueue();
        return res.status(200).json({
          status: "accepted",
          queued: true
        });
      } catch (error) {
        logger.error("Webhook processing error:", error);
        return res.status(500).json({ error: "Internal server error" });
      }
    });
    this.app.use((req, res) => {
      res.status(404).json({ error: "Not found" });
    });
  }
  verifyWebhookSignature(req) {
    if (!this.config.webhookSecret) {
      logger.warn("No webhook secret configured, accepting all webhooks");
      return true;
    }
    const signature = req.headers["linear-signature"];
    if (!signature) {
      return false;
    }
    const hash = crypto.createHmac("sha256", this.config.webhookSecret).update(req.body).digest("hex");
    return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(hash));
  }
  async processQueue() {
    if (this.isProcessing || this.eventQueue.length === 0) {
      return;
    }
    this.isProcessing = true;
    while (this.eventQueue.length > 0) {
      const event = this.eventQueue.shift();
      try {
        await this.handleWebhookEvent(event);
      } catch (error) {
        logger.error(`Failed to process event: ${event.type}`, error);
      }
    }
    this.isProcessing = false;
  }
  async handleWebhookEvent(payload) {
    const { type, action, data } = payload;
    switch (type) {
      case "Issue":
        await this.handleIssueEvent(action, data);
        break;
      case "Comment":
        await this.handleCommentEvent(action, data);
        break;
      case "Project":
        await this.handleProjectEvent(action, data);
        break;
      default:
        logger.debug(`Unhandled event type: ${type}`);
    }
  }
  async handleIssueEvent(action, data) {
    const issue = data;
    switch (action) {
      case "create":
        logger.info(
          `New issue created: ${issue.identifier} - ${issue.title}`
        );
        await this.syncService.syncIssueToLocal(issue);
        break;
      case "update":
        logger.info(`Issue updated: ${issue.identifier} - ${issue.title}`);
        await this.syncService.syncIssueToLocal(issue);
        break;
      case "remove":
        logger.info(`Issue removed: ${issue.identifier}`);
        await this.syncService.removeLocalIssue(issue.identifier);
        break;
      default:
        logger.debug(`Unhandled issue action: ${action}`);
    }
  }
  async handleCommentEvent(action, data) {
    logger.debug(`Comment event: ${action}`, { issueId: data.issue?.id });
  }
  async handleProjectEvent(action, data) {
    logger.debug(`Project event: ${action}`, { projectId: data.id });
  }
  async start() {
    return new Promise((resolve) => {
      this.server = this.app.listen(
        this.config.port,
        this.config.host,
        () => {
          console.log(
            chalk.green("\u2713") + chalk.bold(" Linear Webhook Server Started")
          );
          console.log(
            chalk.cyan("  URL: ") + `http://${this.config.host}:${this.config.port}/webhook/linear`
          );
          console.log(
            chalk.cyan("  Health: ") + `http://${this.config.host}:${this.config.port}/health`
          );
          if (!this.config.webhookSecret) {
            console.log(
              chalk.yellow(
                "  \u26A0 Warning: No webhook secret configured (insecure)"
              )
            );
          }
          resolve();
        }
      );
    });
  }
  async stop() {
    return new Promise((resolve) => {
      if (this.server) {
        this.server.close(() => {
          logger.info("Webhook server stopped");
          resolve();
        });
      } else {
        resolve();
      }
    });
  }
}
if (process.argv[1] === new URL(import.meta.url).pathname) {
  const server = new LinearWebhookServer();
  server.start().catch((error) => {
    console.error(chalk.red("Failed to start webhook server:"), error);
    process.exit(1);
  });
  process.on("SIGINT", async () => {
    console.log(chalk.yellow("\n\nShutting down webhook server..."));
    await server.stop();
    process.exit(0);
  });
}
export {
  LinearWebhookServer
};
//# sourceMappingURL=webhook-server.js.map
