import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { logger } from "../../core/monitoring/logger.js";
import crypto from "crypto";
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 LinearWebhookHandler {
  syncEngine;
  taskStore;
  webhookSecret;
  constructor(webhookSecret) {
    this.webhookSecret = webhookSecret || process.env["LINEAR_WEBHOOK_SECRET"];
  }
  /**
   * Set the sync engine for processing webhooks
   */
  setSyncEngine(syncEngine) {
    this.syncEngine = syncEngine;
  }
  /**
   * Set the task store for direct updates
   */
  setTaskStore(taskStore) {
    this.taskStore = taskStore;
  }
  /**
   * Verify webhook signature
   */
  verifySignature(body, signature) {
    if (!this.webhookSecret) {
      logger.warn("No webhook secret configured, skipping verification");
      return true;
    }
    const hmac = crypto.createHmac("sha256", this.webhookSecret);
    hmac.update(body);
    const expectedSignature = hmac.digest("hex");
    return signature === expectedSignature;
  }
  /**
   * Validate webhook payload structure
   */
  validateWebhookPayload(payload) {
    if (!payload || typeof payload !== "object") return null;
    const p = payload;
    if (!p.action || typeof p.action !== "string") return null;
    if (!p.type || typeof p.type !== "string") return null;
    if (!p.data || typeof p.data !== "object") return null;
    if (!p.data.id || typeof p.data.id !== "string") return null;
    if (p.data.title && typeof p.data.title === "string") {
      p.data.title = p.data.title.substring(0, 500);
    }
    if (p.data.description && typeof p.data.description === "string") {
      p.data.description = p.data.description.substring(0, 5e3);
    }
    return p;
  }
  /**
   * Process incoming webhook
   */
  async processWebhook(payload) {
    const validatedPayload = this.validateWebhookPayload(payload);
    if (!validatedPayload) {
      logger.error("Invalid webhook payload received");
      throw new Error("Invalid webhook payload");
    }
    logger.info("Processing Linear webhook", {
      action: validatedPayload.action,
      type: validatedPayload.type,
      id: validatedPayload.data.id
    });
    payload = validatedPayload;
    if (payload.type !== "Issue") {
      logger.info(`Ignoring webhook for type: ${payload.type}`);
      return;
    }
    switch (payload.action) {
      case "create":
        await this.handleIssueCreated(payload);
        break;
      case "update":
        await this.handleIssueUpdated(payload);
        break;
      case "remove":
        await this.handleIssueRemoved(payload);
        break;
      default:
        logger.warn(`Unknown webhook action: ${payload.action}`);
    }
  }
  /**
   * Handle issue created in Linear
   */
  async handleIssueCreated(payload) {
    logger.info("Linear issue created", {
      identifier: payload.data.identifier
    });
    if (!this.shouldSyncIssue(payload.data)) {
      return;
    }
    logger.info("Would create StackMemory task for Linear issue", {
      identifier: payload.data.identifier,
      title: payload.data.title
    });
    if (this.taskStore) {
      try {
        const taskId = this.taskStore.createTask({
          frameId: "linear-import",
          // Special frame for Linear imports
          title: payload.data.title || "Untitled Linear Issue",
          description: payload.data.description || "",
          priority: this.mapLinearPriorityToStackMemory(payload.data.priority),
          assignee: payload.data.assignee?.email,
          tags: payload.data.labels?.map((l) => l.name) || []
        });
        this.storeMapping(taskId, payload.data.id);
        logger.info("Created StackMemory task from Linear issue", {
          stackmemoryId: taskId,
          linearId: payload.data.id
        });
      } catch (error) {
        logger.error("Failed to create task from Linear issue", {
          error: error instanceof Error ? error.message : String(error)
        });
      }
    }
  }
  /**
   * Handle issue updated in Linear
   */
  async handleIssueUpdated(payload) {
    logger.info("Linear issue updated", {
      identifier: payload.data.identifier
    });
    if (!this.syncEngine) {
      logger.warn("No sync engine configured, cannot process update");
      return;
    }
    const mapping = this.findMappingByLinearId(payload.data.id);
    if (!mapping) {
      logger.info("No mapping found for Linear issue", { id: payload.data.id });
      return;
    }
    const task = this.taskStore?.getTask(mapping.stackmemoryId);
    if (!task) {
      logger.warn("StackMemory task not found", { id: mapping.stackmemoryId });
      return;
    }
    let newStatus;
    if (payload.data.state) {
      const mappedStatus = this.mapLinearStateToStatus(payload.data.state);
      if (mappedStatus !== task.status) {
        newStatus = mappedStatus;
      }
    }
    if (payload.data.completedAt) {
      newStatus = "completed";
    }
    if (newStatus) {
      this.taskStore?.updateTaskStatus(
        mapping.stackmemoryId,
        newStatus,
        "Linear webhook update"
      );
      logger.info("Updated StackMemory task status from webhook", {
        taskId: mapping.stackmemoryId,
        newStatus
      });
    }
    if (payload.data.title && payload.data.title !== task.title) {
      logger.info(
        "Task title changed in Linear but not updated in StackMemory",
        {
          taskId: mapping.stackmemoryId,
          oldTitle: task.title,
          newTitle: payload.data.title
        }
      );
    }
  }
  /**
   * Handle issue removed in Linear
   */
  async handleIssueRemoved(payload) {
    logger.info("Linear issue removed", {
      identifier: payload.data.identifier
    });
    const mapping = this.findMappingByLinearId(payload.data.id);
    if (!mapping) {
      logger.info("No mapping found for removed Linear issue");
      return;
    }
    this.taskStore?.updateTaskStatus(
      mapping.stackmemoryId,
      "cancelled",
      "Linear issue deleted"
    );
    logger.info("Marked StackMemory task as cancelled due to Linear deletion", {
      taskId: mapping.stackmemoryId
    });
  }
  /**
   * Check if we should sync this issue
   */
  shouldSyncIssue(issue) {
    if (!issue.title) {
      return false;
    }
    if (issue.state?.type === "canceled" || issue.state?.type === "archived") {
      return false;
    }
    return true;
  }
  /**
   * Find mapping by Linear ID
   */
  findMappingByLinearId(linearId) {
    const mapping = this.taskMappings.get(linearId);
    if (mapping) {
      return { stackmemoryId: mapping, linearId };
    }
    return null;
  }
  // In-memory task mappings (Linear ID -> StackMemory ID)
  taskMappings = /* @__PURE__ */ new Map();
  /**
   * Store mapping between Linear and StackMemory IDs
   */
  storeMapping(stackmemoryId, linearId) {
    this.taskMappings.set(linearId, stackmemoryId);
  }
  /**
   * Map Linear priority to StackMemory priority
   */
  mapLinearPriorityToStackMemory(priority) {
    if (!priority) return "medium";
    if (priority <= 1) return "urgent";
    if (priority === 2) return "high";
    if (priority === 3) return "medium";
    return "low";
  }
  /**
   * Map Linear state to StackMemory status
   */
  mapLinearStateToStatus(state) {
    const stateType = state.type?.toLowerCase() || state.name?.toLowerCase();
    switch (stateType) {
      case "backlog":
      case "unstarted":
        return "pending";
      case "started":
      case "in progress":
        return "in_progress";
      case "completed":
      case "done":
        return "completed";
      case "canceled":
      case "cancelled":
        return "cancelled";
      default:
        return "pending";
    }
  }
  /**
   * Map Linear priority to StackMemory priority
   */
  mapLinearPriorityToPriority(priority) {
    return 5 - priority;
  }
}
export {
  LinearWebhookHandler
};
//# sourceMappingURL=webhook.js.map
