/**
 * Session filtering for memory-tdai.
 *
 * Decides whether a session should be ignored by the memory plugin
 * (capture, recall, pipeline scheduling). All skip rules are compiled
 * into a flat list of matchers at construction time — zero per-call overhead.
 */

/**
 * @typedef {Object} AgentHookContext
 * @property {string} [sessionKey]
 * @property {string} [sessionId]
 */

/**
 * @typedef {(sessionKey: string) => boolean} SessionKeyMatcher
 */

// ============================
// Built-in skip rules (always active)
// ============================

/**
 * Hard-coded matchers that identify internal / non-user sessions.
 * These are always applied regardless of user configuration.
 * @type {SessionKeyMatcher[]}
 */
const BUILTIN_MATCHERS = [
  // Scene extraction runner sessions
  (key) => key.includes(":memory-scene-extract-"),
  // OpenClaw subagent sessions
  (key) => key.includes(":subagent:"),
  // Temporary / internal utility sessions (e.g. temp:slug-generator)
  (key) => key.startsWith("temp:"),
];

// ============================
// Glob → matcher compiler
// ============================

/**
 * Turn a simple glob pattern (only `*` supported) into a matcher
 * that tests the full sessionKey.
 *
 * Since sessionKeys look like `agent:<agentId>:...`, we match the
 * glob against the whole key so users can write patterns like
 * `bench-judge-*` (matched anywhere) or more specific ones.
 * @param {string} pattern
 * @returns {SessionKeyMatcher}
 */
function globToMatcher(pattern) {
  const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
  const re = new RegExp(escaped);
  return (key) => re.test(key);
}

// ============================
// SessionFilter
// ============================

/**
 * Unified filter: construct once at plugin startup, then call
 * `shouldSkip(sessionKey)` or `shouldSkipCtx(ctx)` at each gate.
 */
export class SessionFilter {
  /** @type {SessionKeyMatcher[]} */
  matchers;

  /**
   * @param {string[]} [excludeAgents]
   */
  constructor(excludeAgents = []) {
    // Merge built-in rules + user-configured exclude patterns into one flat list
    const userMatchers = excludeAgents
      .map((p) => p.trim())
      .filter((p) => p.length > 0)
      .map(globToMatcher);

    this.matchers = [...BUILTIN_MATCHERS, ...userMatchers];
  }

  /**
   * Should this sessionKey be skipped?
   * @param {string} sessionKey
   * @returns {boolean}
   */
  shouldSkip(sessionKey) {
    return this.matchers.some((m) => m(sessionKey));
  }

  /**
   * Should this hook context be skipped?
   * @param {AgentHookContext} ctx
   * @returns {boolean}
   */
  shouldSkipCtx(ctx) {
    if (!ctx.sessionKey) return true;
    if (ctx.sessionId?.startsWith("memory-")) return true;
    return this.shouldSkip(ctx.sessionKey);
  }
}
