const fs = require('fs');
const path = require('path');

const kanbanStore = require('./kanbanStore.js');
const taskStore = require('./taskStore.js');

function listInboxNames(paths) {
  const inboxDir = path.join(paths.teamDir, 'inboxes');
  let entries = [];
  try {
    entries = fs.readdirSync(inboxDir);
  } catch (error) {
    if (error && error.code === 'ENOENT') {
      return [];
    }
    throw error;
  }

  return entries
    .filter((name) => name.endsWith('.json') && !name.startsWith('.'))
    .map((name) => name.replace(/\.json$/, ''));
}

function readInboxMessages(paths) {
  const messages = [];

  for (const member of listInboxNames(paths)) {
    const inboxPath = path.join(paths.teamDir, 'inboxes', `${member}.json`);
    let parsed;
    try {
      parsed = JSON.parse(fs.readFileSync(inboxPath, 'utf8'));
    } catch {
      continue;
    }

    if (!Array.isArray(parsed)) {
      continue;
    }

    for (const item of parsed) {
      if (!item || typeof item !== 'object') {
        continue;
      }

      if (
        typeof item.from !== 'string' ||
        typeof item.text !== 'string' ||
        typeof item.timestamp !== 'string'
      ) {
        continue;
      }

      messages.push({
        from: item.from,
        to: typeof item.to === 'string' ? item.to : member,
        text: item.text,
        timestamp: item.timestamp,
        summary: typeof item.summary === 'string' ? item.summary : undefined,
        messageId: typeof item.messageId === 'string' ? item.messageId : undefined,
        source: typeof item.source === 'string' ? item.source : undefined,
      });
    }
  }

  messages.sort((a, b) => {
    const bt = Date.parse(b.timestamp);
    const at = Date.parse(a.timestamp);
    if (Number.isNaN(bt) || Number.isNaN(at)) {
      return 0;
    }
    return bt - at;
  });

  return messages;
}

function isAutomatedCommentNotification(message) {
  const summary = typeof message.summary === 'string' ? message.summary : '';
  if (!/^Comment on #[A-Za-z0-9-]+/.test(summary)) return false;

  const text = typeof message.text === 'string' ? message.text : '';
  if (!text) return false;

  if (text.includes('Reply to this comment using:')) return true;
  if (text.startsWith('Comment on task #')) return true;
  if (text.startsWith('New comment from user on your task #')) return true;
  return false;
}

function syncLinkedComments(paths, tasks, messages) {
  const taskIdPattern = /#([A-Za-z0-9-]+)/g;
  const tasksById = new Map();
  const processedTexts = new Set();
  let linkedCommentsCreated = 0;

  for (const task of tasks) {
    tasksById.set(task.id, task);
    if (task.displayId) {
      tasksById.set(task.displayId, task);
    }
  }

  for (const message of messages) {
    if (!message.messageId || !message.summary || message.from === 'user') continue;
    if (message.source === 'lead_session' || message.source === 'lead_process') continue;
    if (message.source === 'system_notification') continue;
    if (isAutomatedCommentNotification(message)) continue;

    const textKey = `${message.from}\0${message.text}`;
    if (processedTexts.has(textKey)) continue;
    processedTexts.add(textKey);

    const taskRefs = new Set();
    for (const match of message.summary.matchAll(taskIdPattern)) {
      taskRefs.add(match[1]);
    }

    for (const taskRef of taskRefs) {
      const task = tasksById.get(taskRef);
      if (!task) continue;

      const commentId = `msg-${message.messageId}`;
      const existingComments = Array.isArray(task.comments) ? task.comments : [];
      if (existingComments.some((comment) => comment.id === commentId)) {
        continue;
      }

      try {
        taskStore.addTaskComment(paths, task.id, message.text, {
          id: commentId,
          author: message.from,
          createdAt: message.timestamp,
        });
        linkedCommentsCreated += 1;
      } catch {
        // Best-effort: reconcile should not fail on individual comment sync writes.
      }
    }
  }

  return linkedCommentsCreated;
}

function reconcileArtifacts(context, options = {}) {
  const garbageCollectKanban = options.garbageCollectKanban !== false;
  const shouldSyncLinkedComments = options.syncLinkedComments !== false;
  const tasks = taskStore.listTasks(context.paths);

  const gcResult = garbageCollectKanban
    ? kanbanStore.garbageCollect(
        context.paths,
        context.teamName,
        new Set(tasks.map((task) => task.id))
      )
    : { staleKanbanEntriesRemoved: 0, staleColumnOrderRefsRemoved: 0 };

  const linkedCommentsCreated = shouldSyncLinkedComments
    ? syncLinkedComments(context.paths, tasks, readInboxMessages(context.paths))
    : 0;

  return {
    staleKanbanEntriesRemoved: gcResult.staleKanbanEntriesRemoved,
    staleColumnOrderRefsRemoved: gcResult.staleColumnOrderRefsRemoved,
    linkedCommentsCreated,
  };
}

module.exports = {
  reconcileArtifacts,
};
