/**
 * Suppress ServiceChannel webhook echo for files uploaded via /attach or /upload.
 * SC auto-generates "Attachment '…' has been added" notes (with AttachmentIds)
 * which would otherwise re-post notes and files into the same Webex WO space.
 */

import { logger } from '../utils/logger.js';

const DEFAULT_TTL_MS = 10 * 60 * 1000;

function normalizeFileName(name) {
  try {
    return decodeURIComponent(String(name || '').trim()).toLowerCase();
  } catch {
    return String(name || '').trim().toLowerCase();
  }
}

function normalizeNoteText(text) {
  return String(text || '').trim();
}

function expiresAtFromTtl(ttlMs = DEFAULT_TTL_MS) {
  return new Date(Date.now() + ttlMs).toISOString();
}

function dbRun(db, sql, params = []) {
  return new Promise((resolve, reject) => {
    db.run(sql, params, function onRun(err) {
      if (err) reject(err);
      else resolve(this);
    });
  });
}

function dbGet(db, sql, params = []) {
  return new Promise((resolve, reject) => {
    db.get(sql, params, (err, row) => (err ? reject(err) : resolve(row ?? null)));
  });
}

export function isScAttachmentAddedNote(noteData) {
  return /^Attachment\s+'.+'\s+has been added\./i.test(normalizeNoteText(noteData));
}

export function extractAttachmentFileNameFromNote(noteData) {
  const m = normalizeNoteText(noteData).match(/^Attachment\s+'([^']+)'\s+has been added\./i);
  return m ? m[1] : null;
}

export async function registerUploadEchoSuppress(
  db,
  workOrderId,
  { attachmentId = null, fileName = null, noteText = null, ttlMs = DEFAULT_TTL_MS } = {}
) {
  if (!db || !workOrderId) return;

  await dbRun(
    db,
    `INSERT INTO upload_echo_suppress (workOrderId, attachmentId, fileName, noteText, expiresAt)
     VALUES (?, ?, ?, ?, ?)`,
    [
      workOrderId,
      attachmentId,
      fileName ? normalizeFileName(fileName) : null,
      noteText ? normalizeNoteText(noteText) : null,
      expiresAtFromTtl(ttlMs),
    ]
  );
}

export async function markAttachmentPosted(db, workOrderId, attachmentId) {
  if (!db || !workOrderId || attachmentId == null) return;
  await dbRun(
    db,
    `INSERT OR IGNORE INTO posted_attachments (workOrderId, attachmentId, postedAt)
     VALUES (?, ?, ?)`,
    [workOrderId, attachmentId, new Date().toISOString()]
  );
}

async function hasActiveSuppress(db, workOrderId, { attachmentIds = [], fileName = null, noteText = null }) {
  const now = new Date().toISOString();
  const ids = (attachmentIds || []).filter((id) => id != null);
  const normalizedName = fileName ? normalizeFileName(fileName) : null;
  const normalizedNote = noteText ? normalizeNoteText(noteText) : null;

  if (normalizedNote) {
    const row = await dbGet(
      db,
      `SELECT 1 FROM upload_echo_suppress
       WHERE workOrderId = ? AND noteText = ? AND expiresAt > ?
       LIMIT 1`,
      [workOrderId, normalizedNote, now]
    );
    if (row) return true;
  }

  if (normalizedName) {
    const row = await dbGet(
      db,
      `SELECT 1 FROM upload_echo_suppress
       WHERE workOrderId = ? AND fileName = ? AND expiresAt > ?
       LIMIT 1`,
      [workOrderId, normalizedName, now]
    );
    if (row) return true;
  }

  for (const id of ids) {
    const row = await dbGet(
      db,
      `SELECT 1 FROM upload_echo_suppress
       WHERE workOrderId = ? AND attachmentId = ? AND expiresAt > ?
       LIMIT 1`,
      [workOrderId, id, now]
    );
    if (row) return true;
  }

  return false;
}

export async function shouldSuppressWebhookNote(db, workOrderId, note = {}) {
  if (!db || !workOrderId || !note) return false;

  const noteData = note.NoteData || note.noteData || '';
  const attachmentIds = note.AttachmentIds || note.attachmentIds || [];

  if (await hasActiveSuppress(db, workOrderId, { noteText: noteData, attachmentIds })) {
    return true;
  }

  if (isScAttachmentAddedNote(noteData)) {
    const fileName = extractAttachmentFileNameFromNote(noteData);
    if (await hasActiveSuppress(db, workOrderId, { fileName, attachmentIds })) {
      logger(
        'uploadEchoSuppress',
        `Suppressing SC attachment note echo for WO ${workOrderId}: ${fileName || noteData}`
      );
      return true;
    }
  }

  return false;
}

export async function shouldSuppressAttachmentPost(db, workOrderId, attachmentIds = []) {
  if (!db || !workOrderId || !attachmentIds?.length) return false;

  const now = new Date().toISOString();
  for (const id of attachmentIds) {
    const row = await dbGet(
      db,
      `SELECT 1 FROM upload_echo_suppress
       WHERE workOrderId = ? AND attachmentId = ? AND expiresAt > ?
       LIMIT 1`,
      [workOrderId, id, now]
    );
    if (!row) return false;
  }

  logger(
    'uploadEchoSuppress',
    `Suppressing SC attachment post echo for WO ${workOrderId}: ids=${attachmentIds.join(',')}`
  );
  return true;
}
