'use strict';

/**
 * ChatGPT conversations.json adapter.
 * Parses the tree-mapped message structure from ChatGPT exports.
 * Usage: Place conversations.json in ~/.walle/imports/chatgpt/
 */

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

const IMPORT_DIR = path.join(process.env.HOME, '.walle', 'imports', 'chatgpt');

function poll(since) {
  const memories = [];
  if (!fs.existsSync(IMPORT_DIR)) return memories;

  const files = fs.readdirSync(IMPORT_DIR).filter(f => f.endsWith('.json'));
  for (const file of files) {
    try {
      const data = JSON.parse(fs.readFileSync(path.join(IMPORT_DIR, file), 'utf8'));
      // ChatGPT exports can be an array or have a .conversations key
      const conversations = Array.isArray(data) ? data : (data.conversations || [data]);

      for (const conv of conversations) {
        if (!conv.mapping) continue;
        const title = conv.title || 'Untitled';
        const createTime = conv.create_time ? new Date(conv.create_time * 1000).toISOString() : null;

        // Walk the message tree
        const messages = extractMessages(conv.mapping);
        if (messages.length === 0) continue;

        // Group into exchange pairs (user question + assistant response)
        // Filter to user/assistant only, pair by scanning for user then next assistant
        let i = 0;
        while (i < messages.length) {
          // Find next user message
          while (i < messages.length && messages[i].role !== 'user') i++;
          if (i >= messages.length) break;
          const userMsg = messages[i];
          i++;
          // Find next assistant message (may not exist)
          const assistantMsg = (i < messages.length && messages[i].role === 'assistant') ? messages[i++] : null;
          const timestamp = userMsg.create_time
            ? new Date(userMsg.create_time * 1000).toISOString()
            : createTime;

          if (since && timestamp && timestamp <= since) continue;

          let content = `> ${userMsg.text || ''}`;
          if (assistantMsg) content += `\n\n${assistantMsg.text || ''}`;

          memories.push({
            source: 'chatgpt',
            source_id: `chatgpt-${conv.id || file}-${memories.length}`,
            content: content.slice(0, 10000),
            timestamp,
            metadata: JSON.stringify({ title, file }),
          });
        }
      }
    } catch (err) {
      console.error(`[chatgpt-adapter] Failed to parse ${file}:`, err.message);
    }
  }
  return memories;
}

function extractMessages(mapping) {
  const messages = [];
  const visited = new Set();

  // Find root node (no parent)
  let rootId = null;
  for (const [id, node] of Object.entries(mapping)) {
    if (!node.parent) { rootId = id; break; }
  }
  if (!rootId) return messages;

  // BFS through the tree
  const queue = [rootId];
  while (queue.length > 0) {
    const nodeId = queue.shift();
    if (visited.has(nodeId)) continue;
    visited.add(nodeId);

    const node = mapping[nodeId];
    if (!node) continue;

    const msg = node.message;
    if (msg && msg.content && msg.content.parts && msg.author) {
      const role = msg.author.role;
      if (role === 'user' || role === 'assistant') {
        const text = msg.content.parts
          .filter(p => typeof p === 'string')
          .join('\n')
          .trim();
        if (text) {
          messages.push({
            role,
            text,
            create_time: msg.create_time,
          });
        }
      }
    }

    // Follow children
    if (node.children) {
      for (const childId of node.children) {
        queue.push(childId);
      }
    }
  }

  return messages;
}

module.exports = { poll };
