import type { AutomationReactionConfig } from '../config/schema.js';

export interface ReactionEvent {
  channel: string;
  senderId: string;
  text: string;
  metadata?: Record<string, unknown>;
}

export interface ReactionMatchResult {
  name: string;
  prompt: string;
}

function getNestedValue(record: Record<string, unknown>, path: string): unknown {
  const segments = path.split('.').filter(Boolean);
  let current: unknown = record;
  for (const segment of segments) {
    if (!current || typeof current !== 'object') {
      return undefined;
    }
    current = (current as Record<string, unknown>)[segment];
  }
  return current;
}

function renderTemplate(template: string, event: ReactionEvent): string {
  return template.replace(/\{\{\s*([^}]+)\s*\}\}/g, (_full, rawKey: string) => {
    const key = rawKey.trim();
    if (key === 'text') {
      return event.text;
    }
    if (key === 'channel') {
      return event.channel;
    }
    if (key === 'sender_id') {
      return event.senderId;
    }
    if (key.startsWith('metadata.')) {
      const value = getNestedValue(event.metadata ?? {}, key.slice('metadata.'.length));
      if (value === undefined || value === null) {
        return '';
      }
      return typeof value === 'string' ? value : JSON.stringify(value);
    }
    return '';
  });
}

function metadataMatches(
  required: Record<string, string>,
  metadata?: Record<string, unknown>,
): boolean {
  if (!metadata) {
    return false;
  }
  for (const [path, expected] of Object.entries(required)) {
    const actual = getNestedValue(metadata, path);
    if (actual === undefined || actual === null) {
      return false;
    }
    if (String(actual) !== expected) {
      return false;
    }
  }
  return true;
}

function ruleMatches(rule: AutomationReactionConfig, event: ReactionEvent): boolean {
  if (!rule.enabled) {
    return false;
  }
  if (rule.on.length > 0 && !rule.on.includes(event.channel)) {
    return false;
  }

  const filter = rule.filter;
  if (!filter) {
    return true;
  }

  if (filter.contains) {
    if (!event.text.toLowerCase().includes(filter.contains.toLowerCase())) {
      return false;
    }
  }

  if (filter.regex) {
    let regex: RegExp;
    try {
      regex = new RegExp(filter.regex, 'i');
    } catch {
      return false;
    }
    if (!regex.test(event.text)) {
      return false;
    }
  }

  if (filter.metadata && !metadataMatches(filter.metadata, event.metadata)) {
    return false;
  }

  return true;
}

/** Find the first matching reaction rule and render its run template. */
export function matchReactionPrompt(
  reactions: AutomationReactionConfig[],
  event: ReactionEvent,
): ReactionMatchResult | null {
  for (const rule of reactions) {
    if (!ruleMatches(rule, event)) {
      continue;
    }
    return {
      name: rule.name,
      prompt: renderTemplate(rule.run, event),
    };
  }
  return null;
}
