#!/usr/bin/env node
/**
 * iMessage Webhook Filter for Clawdbot
 * 
 * Filters BlueBubbles webhooks before they reach Clawdbot.
 * Only forwards messages that contain "Buba" (case insensitive).
 * 
 * Usage: node filter.js
 * 
 * Config via env vars:
 *   FILTER_PORT=18790
 *   CLAWDBOT_URL=http://127.0.0.1:18789/bluebubbles-webhook
 *   MENTION_PATTERN=buba (case insensitive)
 */

const http = require('http');
const https = require('https');

const FILTER_PORT = process.env.FILTER_PORT || 18790;
const CLAWDBOT_URL = process.env.CLAWDBOT_URL || 'http://127.0.0.1:18789/bluebubbles-webhook';
const MENTION_PATTERN = new RegExp(process.env.MENTION_PATTERN || '\\bbuba\\b', 'i');

// Track which chats have said the password
const unlockedChats = new Set();
const PASSWORD = 'TANGO12';

function log(msg) {
  console.log(`[${new Date().toISOString()}] ${msg}`);
}

function extractMessageText(body) {
  try {
    // BlueBubbles webhook payload structure
    if (body.data?.text) return body.data.text;
    if (body.message?.text) return body.message.text;
    if (body.text) return body.text;
    // Try to find text in nested structure
    const str = JSON.stringify(body);
    return str;
  } catch (e) {
    return '';
  }
}

function extractChatId(body) {
  try {
    if (body.data?.chatGuid) return body.data.chatGuid;
    if (body.data?.chat?.guid) return body.data.chat.guid;
    if (body.chatGuid) return body.chatGuid;
    if (body.chat?.guid) return body.chat.guid;
    return 'unknown';
  } catch (e) {
    return 'unknown';
  }
}

function shouldForward(body) {
  const text = extractMessageText(body);
  const chatId = extractChatId(body);
  
  // Check for password
  if (text.includes(PASSWORD)) {
    unlockedChats.add(chatId);
    log(`Chat ${chatId} UNLOCKED with password`);
  }
  
  // Always forward if it contains "Buba"
  if (MENTION_PATTERN.test(text)) {
    log(`FORWARD: Message contains mention pattern`);
    return true;
  }
  
  // Check if this is a non-message event (typing, read receipt, etc.)
  // These should be forwarded
  const eventType = body.type || body.event || '';
  if (eventType && !eventType.includes('message')) {
    log(`FORWARD: Non-message event (${eventType})`);
    return true;
  }
  
  // Block messages without mention
  log(`BLOCK: No mention found in message`);
  return false;
}

function forwardToClawdbot(body, query, callback) {
  const url = new URL(CLAWDBOT_URL);
  
  // Preserve query params (password, guid, etc.)
  if (query) {
    const params = new URLSearchParams(query);
    params.forEach((value, key) => url.searchParams.set(key, value));
  }
  
  const payload = JSON.stringify(body);
  const protocol = url.protocol === 'https:' ? https : http;
  
  const options = {
    hostname: url.hostname,
    port: url.port || (url.protocol === 'https:' ? 443 : 80),
    path: url.pathname + url.search,
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Content-Length': Buffer.byteLength(payload)
    }
  };
  
  const req = protocol.request(options, (res) => {
    let data = '';
    res.on('data', chunk => data += chunk);
    res.on('end', () => {
      log(`Clawdbot responded: ${res.statusCode}`);
      callback(null, res.statusCode, data);
    });
  });
  
  req.on('error', (err) => {
    log(`Forward error: ${err.message}`);
    callback(err);
  });
  
  req.write(payload);
  req.end();
}

const server = http.createServer((req, res) => {
  // Health check
  if (req.method === 'GET' && req.url === '/health') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ status: 'ok', unlockedChats: unlockedChats.size }));
    return;
  }
  
  // Only handle POST requests
  if (req.method !== 'POST') {
    res.writeHead(405);
    res.end('Method not allowed');
    return;
  }
  
  let body = '';
  req.on('data', chunk => body += chunk);
  req.on('end', () => {
    let parsed;
    try {
      parsed = JSON.parse(body);
    } catch (e) {
      log(`Parse error: ${e.message}`);
      res.writeHead(400);
      res.end('Invalid JSON');
      return;
    }
    
    const query = req.url.split('?')[1] || '';
    
    if (shouldForward(parsed)) {
      forwardToClawdbot(parsed, query, (err, statusCode, data) => {
        if (err) {
          res.writeHead(502);
          res.end('Forward failed');
        } else {
          res.writeHead(statusCode || 200, { 'Content-Type': 'application/json' });
          res.end(data || '{"status":"forwarded"}');
        }
      });
    } else {
      // Return success but don't forward
      res.writeHead(200, { 'Content-Type': 'application/json' });
      res.end('{"status":"filtered","reason":"no_mention"}');
    }
  });
});

server.listen(FILTER_PORT, '127.0.0.1', () => {
  log(`iMessage filter running on port ${FILTER_PORT}`);
  log(`Forwarding to: ${CLAWDBOT_URL}`);
  log(`Mention pattern: ${MENTION_PATTERN}`);
  log(`Password: ${PASSWORD}`);
});

process.on('SIGTERM', () => {
  log('Shutting down...');
  server.close(() => process.exit(0));
});

process.on('SIGINT', () => {
  log('Shutting down...');
  server.close(() => process.exit(0));
});
