'use strict';

const fs = require('node:fs');
const path = require('node:path');
const crypto = require('node:crypto');

function sha256(content) {
  return crypto.createHash('sha256').update(content).digest('hex');
}

function encodeRepoPath(repoRoot) {
  return path.resolve(repoRoot).replace(/[\\/]/g, '-');
}

function titleFromName(name, description) {
  if (typeof name === 'string' && name.trim().length > 0) {
    const normalized = name.trim().replace(/[-_]+/g, ' ');
    return normalized.charAt(0).toUpperCase() + normalized.slice(1);
  }

  if (typeof description === 'string' && description.trim().length > 0) {
    return description.trim().replace(/[.?!]+$/, '');
  }

  return 'Untitled';
}

function parseFrontmatter(content) {
  const match = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/u.exec(content);
  if (!match) {
    return { data: {}, body: content };
  }

  const data = {};
  const lines = match[1].split('\n');

  for (let index = 0; index < lines.length; index += 1) {
    const line = lines[index];
    const metadataMatch = /^metadata:\s*$/.exec(line);
    if (metadataMatch) {
      const metadata = {};
      index += 1;
      while (index < lines.length) {
        const nested = /^ {2}([A-Za-z0-9_-]+):\s*(.*)\s*$/.exec(lines[index]);
        if (!nested) {
          index -= 1;
          break;
        }
        metadata[nested[1]] = nested[2];
        index += 1;
      }
      data.metadata = metadata;
      continue;
    }

    const field = /^([A-Za-z0-9_-]+):\s*(.*)\s*$/.exec(line);
    if (field) {
      data[field[1]] = field[2];
    }
  }

  return { data, body: match[2].replace(/^\n/, '') };
}

function serializeConcept(frontmatter, body) {
  const lines = [
    '---',
    `type: ${frontmatter.type}`,
    `title: ${frontmatter.title}`,
    `description: ${frontmatter.description}`,
    `scope: ${frontmatter.scope}`,
    `okf_id: ${frontmatter.okf_id}`,
    `okf_source: ${frontmatter.okf_source}`,
    `origin_filename: ${frontmatter.origin_filename}`,
    `origin_hash: ${frontmatter.origin_hash}`,
    '---',
    '',
    body.replace(/\s+$/u, ''),
    '',
  ];

  return lines.join('\n');
}

function ensureDir(dirPath) {
  fs.mkdirSync(dirPath, { recursive: true });
}

function atomicWrite(filePath, content) {
  ensureDir(path.dirname(filePath));
  const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
  fs.writeFileSync(tempPath, content);
  fs.renameSync(tempPath, filePath);
}

function isOkfOrigin(data) {
  return typeof data.okf_source === 'string' && data.okf_source !== 'claude-memory';
}

function destinationRoot(repoRoot, runSlug) {
  if (typeof runSlug === 'string' && runSlug.length > 0) {
    return path.join(repoRoot, 'runstate', runSlug, 'okf', 'concepts');
  }

  return path.join(repoRoot, '.okf', 'concepts');
}

function conceptScope(runSlug) {
  return typeof runSlug === 'string' && runSlug.length > 0 ? 'job' : 'project';
}

function normalizeMemoryDocument(content, filename, scope) {
  const parsed = parseFrontmatter(content);
  const recordedName = parsed.data.name || parsed.data.metadata?.name;
  const okfId = parsed.data.okf_id || recordedName || path.basename(filename, path.extname(filename));
  const type = parsed.data.type || parsed.data.metadata?.type || 'reference';
  const description = parsed.data.description || parsed.data.metadata?.description || 'Captured from claude memory.';
  const body = parsed.body.replace(/^\s+/u, '').replace(/\s+$/u, '');
  const originHash = sha256(body);

  return {
    okfId,
    okf_id: okfId,
    type,
    description,
    title: parsed.data.title || titleFromName(recordedName || okfId, description),
    scope,
    okf_source: 'claude-memory',
    origin_filename: filename,
    origin_hash: originHash,
    body,
    parsed,
  };
}

function captureClaudeMemory(options = {}) {
  const homeDir = path.resolve(options.homeDir || process.env.HOME || '');
  const repoRoot = path.resolve(options.repoRoot || process.cwd());
  const runSlug = options.runSlug;
  const encodedRepo = encodeRepoPath(repoRoot);
  const memoryDir = path.join(homeDir, '.claude', 'projects', encodedRepo, 'memory');
  const result = { ingested: [], skipped: [] };

  if (!fs.existsSync(memoryDir)) {
    return result;
  }

  const scope = conceptScope(runSlug);
  const targetRoot = destinationRoot(repoRoot, runSlug);
  const memoryFiles = fs.readdirSync(memoryDir)
    .filter((name) => name.endsWith('.md'))
    .sort();

  for (const fileName of memoryFiles) {
    const sourcePath = path.join(memoryDir, fileName);
    const sourceContent = fs.readFileSync(sourcePath, 'utf8');
    const parsedSource = parseFrontmatter(sourceContent);

    if (isOkfOrigin(parsedSource.data)) {
      result.skipped.push({ source: sourcePath, reason: 'okf-origin' });
      continue;
    }

    const normalized = normalizeMemoryDocument(sourceContent, fileName, scope);
    const conceptPath = path.join(targetRoot, `${normalized.okfId}.md`);

    if (!fs.existsSync(conceptPath)) {
      const conceptContent = serializeConcept(normalized, normalized.body);
      atomicWrite(conceptPath, conceptContent);
      result.ingested.push({
        source: sourcePath,
        destination: conceptPath,
        scope,
        okfId: normalized.okfId,
      });
      continue;
    }

    const existingContent = fs.readFileSync(conceptPath, 'utf8');
    const existing = parseFrontmatter(existingContent);
    const existingBody = existing.body.replace(/^\s+/u, '').replace(/\s+$/u, '');

    if (existingBody === normalized.body) {
      result.skipped.push({ source: sourcePath, destination: conceptPath, reason: 'duplicate-body' });
      continue;
    }

    if (existing.data.okf_id === normalized.okfId && existing.data.origin_hash === normalized.origin_hash) {
      result.skipped.push({ source: sourcePath, destination: conceptPath, reason: 'duplicate-hash' });
      continue;
    }

    const mergePath = path.join(targetRoot, `${normalized.okfId}.needs-merge.md`);
    const mergeContent = serializeConcept({
      ...normalized,
      title: `${normalized.title} needs merge`,
    }, normalized.body);
    atomicWrite(mergePath, mergeContent);
    result.skipped.push({ source: sourcePath, destination: conceptPath, merge: mergePath, reason: 'needs-merge' });
  }

  return result;
}

module.exports = {
  captureClaudeMemory,
};
