/**
 * CLI shim creation + PATH injection for non-Desktop installs.
 * Mirrors desktop/src/install-cli-shim.ts but uses only Node.js APIs (no Electron).
 *
 * Creates ~/.mindos/bin/mindos and injects PATH into shell rc files
 * so AI Agents (Claude Code, Cursor, etc.) can find the `mindos` command.
 */
import {
  existsSync,
  readFileSync,
  writeFileSync,
  appendFileSync,
  mkdirSync,
  chmodSync,
} from 'node:fs';
import { execFileSync } from 'node:child_process';
import { resolve, delimiter } from 'node:path';
import { homedir, platform } from 'node:os';
import { CLI_PATH } from './constants.js';

const SHELL_MARKER = '# MindOS CLI';
const home = homedir();

function shimDir() {
  return resolve(home, '.mindos', 'bin');
}

function shimPath() {
  return resolve(shimDir(), platform() === 'win32' ? 'mindos.cmd' : 'mindos');
}

function pathDelimiterForPlatform() {
  return platform() === 'win32' ? ';' : delimiter;
}

function normalizePathDirForCompare(value) {
  const trimmed = String(value || '').trim();
  if (platform() === 'win32') {
    return trimmed.replace(/[\\/]+$/g, '').toLowerCase();
  }
  return trimmed.replace(/\/+$/g, '');
}

function shellSingleQuote(s) {
  return `'${s.replace(/'/g, `'\"'\"'`)}'`;
}

export function escapeCmdSetValue(value) {
  return value
    .replace(/\^/g, '^^')
    .replace(/%/g, '%%')
    .replace(/!/g, '^^!');
}

function writeUnixShim(cliJs) {
  const cliLit = shellSingleQuote(cliJs);
  const script = `#!/bin/sh
# Generated by MindOS CLI — overwritten on each mindos start.

cd "$HOME" 2>/dev/null || true

CLI=${cliLit}

if [ ! -f "$CLI" ]; then
  NPM_ROOT=$(npm root -g 2>/dev/null)
  NPM_CLI="\${NPM_ROOT}/@geminilight/mindos/bin/cli.js"
  if [ -f "$NPM_CLI" ]; then
    CLI="$NPM_CLI"
  else
    echo "mindos: CLI not found. Reinstall: npm install -g @geminilight/mindos" >&2
    exit 127
  fi
fi

if [ -x "$HOME/.mindos/node/bin/node" ]; then
  exec "$HOME/.mindos/node/bin/node" "$CLI" "$@"
fi
if command -v node >/dev/null 2>&1; then
  exec node "$CLI" "$@"
fi
echo "mindos: Node.js not found. Install Node 18+ or run MindOS Desktop (it installs Node under ~/.mindos/node)." >&2
exit 127
`;
  mkdirSync(shimDir(), { recursive: true });
  writeFileSync(shimPath(), script, 'utf-8');
  try { chmodSync(shimPath(), 0o755); } catch { /* ignore */ }
}

function writeWindowsShim(cliJs) {
  const cliEsc = escapeCmdSetValue(cliJs);
  const script = `@echo off\r
rem Generated by MindOS CLI — overwritten on each mindos start.\r
setlocal\r
set "CLI=${cliEsc}"\r
if not exist "%CLI%" (\r
  for /f "delims=" %%R in ('npm root -g 2^>nul') do set "NPM_CLI=%%R\\@geminilight\\mindos\\bin\\cli.js"\r
  if defined NPM_CLI if exist "%NPM_CLI%" set "CLI=%NPM_CLI%"\r
)\r
if not exist "%CLI%" (\r
  echo mindos: CLI not found. Reinstall: npm install -g @geminilight/mindos >&2\r
  exit /b 127\r
)\r
set "MINDOS_NODE=%USERPROFILE%\\.mindos\\node\\node.exe"\r
if exist "%MINDOS_NODE%" (\r
  "%MINDOS_NODE%" "%CLI%" %*\r
  exit /b %ERRORLEVEL%\r
)\r
where node >nul 2>nul\r
if %ERRORLEVEL% equ 0 (\r
  node "%CLI%" %*\r
  exit /b %ERRORLEVEL%\r
)\r
echo mindos: Node.js not found. Install Node 18+ or run MindOS Desktop. >&2\r
exit /b 127\r
`;
  mkdirSync(shimDir(), { recursive: true });
  writeFileSync(shimPath(), script, 'utf-8');
}

function appendPathWindowsProfileFallback(binDir) {
  try {
    const psProfileDir = resolve(home, 'Documents', 'WindowsPowerShell');
    mkdirSync(psProfileDir, { recursive: true });
    const psProfile = resolve(psProfileDir, 'Microsoft.PowerShell_profile.ps1');
    const psBlock = `\n${SHELL_MARKER}\n$env:PATH = "$env:USERPROFILE\\.mindos\\bin;$env:PATH"\n`;

    let needsWrite = !existsSync(psProfile);
    if (!needsWrite) {
      const content = readFileSync(psProfile, 'utf-8');
      needsWrite = !content.includes(SHELL_MARKER) && !content.includes('.mindos\\bin');
    }
    if (needsWrite) {
      appendFileSync(psProfile, psBlock, 'utf-8');
      return true;
    }
  } catch { /* best effort */ }
  return false;
}

/**
 * On Windows, add ~/.mindos/bin to the user PATH registry (idempotent).
 * Falls back to a PowerShell profile snippet if registry update is unavailable.
 */
function appendPathWindows() {
  const binDir = shimDir();
  const normalizedBinDir = normalizePathDirForCompare(binDir);
  const dirs = (process.env.PATH || '').split(pathDelimiterForPlatform());
  if (dirs.some(d => normalizePathDirForCompare(d) === normalizedBinDir)) return false;

  try {
    const psOpts = { encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] };
    const currentPath = execFileSync('powershell.exe', [
      '-NoProfile',
      '-Command',
      '[Environment]::GetEnvironmentVariable("Path", "User")',
    ], psOpts).trim();

    const entries = currentPath.split(';').map((entry) => entry.trim().toLowerCase()).filter(Boolean);
    if (entries.includes(binDir.toLowerCase())) return false;

    const newPath = currentPath ? `${binDir};${currentPath}` : binDir;
    const escaped = newPath.replace(/'/g, "''");
    execFileSync('powershell.exe', [
      '-NoProfile',
      '-Command',
      `[Environment]::SetEnvironmentVariable('Path', '${escaped}', 'User')`,
    ], psOpts);
    return true;
  } catch {
    return appendPathWindowsProfileFallback(binDir);
  }
}

/**
 * Append ~/.mindos/bin to PATH in relevant shell rc files (idempotent).
 * AI Agents run commands via non-interactive shells:
 * - Non-interactive zsh reads ~/.zshenv (NOT ~/.zshrc)
 * - Non-interactive bash reads ~/.bashrc (some systems) or nothing
 * - Fish reads ~/.config/fish/conf.d/*.fish always
 */
function appendPathToShellRc() {
  if (platform() === 'win32') {
    return appendPathWindows();
  }

  const block = `\n${SHELL_MARKER}\nexport PATH="$HOME/.mindos/bin:$PATH"\n`;

  const targets =
    platform() === 'darwin'
      ? [
          { name: '.zshenv',       mustCreate: true },
          { name: '.zshrc',        mustCreate: false },
          { name: '.bashrc',       mustCreate: true },
          { name: '.bash_profile', mustCreate: false },
        ]
      : [
          { name: '.bashrc',  mustCreate: true },
          { name: '.zshenv',  mustCreate: true },
          { name: '.zshrc',   mustCreate: false },
          { name: '.profile', mustCreate: false },
        ];

  let appended = false;

  for (const { name, mustCreate } of targets) {
    const full = resolve(home, name);
    const fileExists = existsSync(full);

    if (!fileExists && !mustCreate) continue;

    if (fileExists) {
      try {
        const content = readFileSync(full, 'utf-8');
        if (content.includes(SHELL_MARKER) || content.includes('# MindOS Desktop')
            || content.includes('.mindos/bin')) continue;
      } catch { continue; }
    }

    try {
      appendFileSync(full, block, 'utf-8');
      appended = true;
    } catch { /* best effort */ }
  }

  // Fish shell support
  try {
    const fishConfD = resolve(home, '.config', 'fish', 'conf.d');
    if (existsSync(fishConfD)) {
      const fishFile = resolve(fishConfD, 'mindos.fish');
      const fishBlock = `${SHELL_MARKER}\nif not contains "$HOME/.mindos/bin" $PATH\n  set -gx PATH "$HOME/.mindos/bin" $PATH\nend\n`;
      let needsWrite = !existsSync(fishFile);
      if (!needsWrite) {
        const content = readFileSync(fishFile, 'utf-8');
        needsWrite = !content.includes(SHELL_MARKER)
          && !content.includes('# MindOS Desktop')
          && !content.includes('.mindos/bin');
      }
      if (needsWrite) {
        writeFileSync(fishFile, fishBlock, 'utf-8');
        appended = true;
      }
    }
  } catch { /* best effort */ }

  return appended;
}

/**
 * Ensure CLI shim exists and PATH is injected. Safe to call on every `mindos start`.
 * Returns true if any changes were made.
 */
export function ensureCliShim() {
  try {
    if (platform() === 'win32') {
      writeWindowsShim(CLI_PATH);
    } else {
      writeUnixShim(CLI_PATH);
    }
  } catch (e) {
    console.warn('[MindOS] Failed to write CLI shim:', e instanceof Error ? e.message : e);
    return false;
  }

  try {
    return appendPathToShellRc();
  } catch (e) {
    console.warn('[MindOS] Failed to append PATH to shell rc:', e instanceof Error ? e.message : e);
    return false;
  }
}

/** Check if ~/.mindos/bin is in the current PATH. */
export function isShimInPath() {
  const dirs = (process.env.PATH || '').split(pathDelimiterForPlatform());
  const binDir = shimDir();
  const normalizedBinDir = normalizePathDirForCompare(binDir);
  return dirs.some((d) => {
    const normalized = normalizePathDirForCompare(d);
    return normalized === normalizedBinDir
      || normalized === normalizePathDirForCompare('$HOME/.mindos/bin')
      || normalized === normalizePathDirForCompare('~/.mindos/bin');
  });
}
