'use strict';

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

const AGENT_WORKTREE_RE = /^(.+?)\/\.(claude|walle)\/worktrees\/([^/]+)\/?$/;

function normalizeCwd(value) {
  const raw = String(value || '').trim();
  if (!raw) return '';
  const expanded = raw.replace(/^~(?=\/|$)/, process.env.HOME || '~');
  return path.normalize(path.isAbsolute(expanded) ? expanded : path.resolve(expanded));
}

function canonicalizeClaudeProjectPath(cwd, opts = {}) {
  const home = opts.homeDir || process.env.HOME || '';
  const resolved = path.resolve(normalizeCwd(cwd) || home || '.');
  try {
    // Claude Code records the kernel-resolved cwd in JSONL metadata on macOS
    // (/tmp -> /private/tmp). Use the same path for project-entry prediction;
    // callers still pass the original cwd to the spawned process.
    return fs.realpathSync(resolved);
  } catch {
    return resolved;
  }
}

function encodeClaudeProjectEntry(cwd, opts = {}) {
  return canonicalizeClaudeProjectPath(cwd, opts)
    .replace(/\/\./g, '/-')
    .replace(/\//g, '-');
}

function claudeProjectDirForCwd(cwd, opts = {}) {
  const home = opts.homeDir || process.env.HOME || '';
  const configDir = opts.claudeConfigDir || path.join(home, '.claude');
  return path.join(configDir, 'projects', encodeClaudeProjectEntry(cwd, opts));
}

function samePath(a, b) {
  const left = normalizeCwd(a);
  const right = normalizeCwd(b);
  return !!left && !!right && left === right;
}

function parseAgentWorktreePath(value) {
  const cwd = normalizeCwd(value);
  if (!cwd) return null;
  const match = cwd.match(AGENT_WORKTREE_RE);
  if (!match) return null;
  return {
    cwd,
    projectRoot: match[1],
    namespace: match[2] === 'walle' ? 'walle' : 'claude',
    worktreeName: match[3],
  };
}

function resolveResumeCwd(cwd, opts = {}) {
  const fsExists = opts.fsExists || fs.existsSync;
  const normalized = normalizeCwd(cwd);
  const parsed = parseAgentWorktreePath(normalized);
  const exists = !!(normalized && fsExists(normalized));

  if (!parsed || exists) {
    return {
      cwd: normalized,
      effectiveCwd: normalized,
      exists,
      isWorktree: !!parsed,
      missingWorktree: false,
      projectRoot: parsed ? parsed.projectRoot : '',
      projectRootExists: parsed ? !!fsExists(parsed.projectRoot) : false,
      namespace: parsed ? parsed.namespace : '',
      worktreeName: parsed ? parsed.worktreeName : '',
    };
  }

  const projectRootExists = !!fsExists(parsed.projectRoot);
  return {
    cwd: normalized,
    effectiveCwd: projectRootExists ? parsed.projectRoot : normalized,
    exists: false,
    isWorktree: true,
    missingWorktree: true,
    projectRoot: parsed.projectRoot,
    projectRootExists,
    namespace: parsed.namespace,
    worktreeName: parsed.worktreeName,
  };
}

function resolveResumeCwdFallback(cwd, opts = {}) {
  const info = resolveResumeCwd(cwd, opts);
  const changed = !!(info.missingWorktree && info.projectRootExists && info.effectiveCwd && info.effectiveCwd !== info.cwd);
  return {
    cwd: changed ? info.effectiveCwd : info.cwd,
    changed,
    info,
  };
}

module.exports = {
  canonicalizeClaudeProjectPath,
  claudeProjectDirForCwd,
  encodeClaudeProjectEntry,
  normalizeCwd,
  parseAgentWorktreePath,
  resolveResumeCwd,
  resolveResumeCwdFallback,
  samePath,
};
