#!/usr/bin/env node
'use strict';

const fs = require('fs');
const path = require('path');
const os = require('os');
const { execSync, spawn } = require('child_process');

// Skip in CI or if SKIP_POSTINSTALL is set
if (process.env.CI || process.env.SKIP_POSTINSTALL || process.env.npm_config_ignore_scripts) {
  process.exit(0);
}

const home = process.env.USERPROFILE || process.env.HOME || '';
if (!home) {
  console.warn('[mcpd] Could not determine home directory, skipping setup');
  process.exit(0);
}

const srcDir = path.resolve(__dirname, '..');
const platform = os.platform();
const binaryName = platform === 'win32' ? 'mcpd.exe' : 'mcpd';

// Find currently installed mcpd binary path
function findInstalledBinary() {
  try {
    if (platform === 'win32') {
      // Use 'where' to find the installed binary
      const result = execSync('where mcpd', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
      const first = result.trim().split('\n')[0].trim();
      if (first && fs.existsSync(first)) return first;
    } else {
      const result = execSync('which mcpd', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
      const first = result.trim().split('\n')[0].trim();
      if (first && fs.existsSync(first)) return first;
    }
  } catch (e) {
    // Not found
  }
  return null;
}

// Check if mcpd daemon is running (any mcpd.exe process)
function isDaemonRunning() {
  try {
    if (platform === 'win32') {
      const result = execSync('tasklist /FI "IMAGENAME eq mcpd.exe" /NH', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
      return result.toLowerCase().includes('mcpd.exe');
    } else {
      const result = execSync('pgrep -f "mcpd"', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
      return result.trim().length > 0;
    }
  } catch (e) {
    return false;
  }
}

// Check if mcpd daemon is running in a specific process
function getMcpdProcesses() {
  try {
    if (platform === 'win32') {
      const result = execSync('wmic process where "name=\'mcpd.exe\'" get ProcessId', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
      return result.trim().split('\n').slice(1).map(s => s.trim()).filter(Boolean);
    } else {
      const result = execSync('pgrep -f "mcpd"', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
      return result.trim().split('\n').filter(Boolean);
    }
  } catch (e) {
    return [];
  }
}

// Try to gracefully stop daemon via socket/IPC
function stopDaemonGracefully() {
  return new Promise((resolve) => {
    try {
      if (platform === 'win32') {
        execSync('taskkill /IM mcpd.exe /T', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
      } else {
        execSync('pkill -f mcpd || true', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
      }
      // Wait briefly for graceful exit
      setTimeout(resolve, 1500);
    } catch (e) {
      // Process may already be gone
      resolve();
    }
  });
}

// Force kill ALL mcpd processes (any path, any command)
function forceKillDaemon() {
  try {
    if (platform === 'win32') {
      execSync('taskkill /F /IM mcpd.exe /T', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
    } else {
      execSync('pkill -9 -f mcpd || true', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
    }
  } catch (e) {
    // Ignore - process may already be gone
  }
}

// Replace the installed binary with the new one
function replaceInstalledBinary() {
  const newBinary = path.join(srcDir, 'bin', platform === 'win32' ? 'win-x64/mcpd.exe' : 'mcpd');
  const installedBinary = findInstalledBinary();

  if (!installedBinary) {
    console.log('[mcpd] No installed binary found, skipping replacement');
    return false;
  }

  if (installedBinary === newBinary) {
    console.log('[mcpd] Binary already up to date');
    return true;
  }

  console.log(`[mcpd] Replacing: ${installedBinary}`);
  try {
    // Backup old binary
    if (fs.existsSync(installedBinary)) {
      try {
        fs.renameSync(installedBinary, installedBinary + '.old');
      } catch (e) {
        // On Windows, rename may fail if locked. Use copy+unlink instead.
        try {
          fs.unlinkSync(installedBinary);
        } catch (e2) {
          console.warn(`[mcpd] Could not remove old binary: ${e2.message}`);
          return false;
        }
      }
    }
    // Copy new binary to installed location
    fs.copyFileSync(newBinary, installedBinary);
    // Set executable permission on Unix
    if (platform !== 'win32') {
      fs.chmodSync(installedBinary, 0o755);
    }
    // Clean up .old file
    const oldPath = installedBinary + '.old';
    if (fs.existsSync(oldPath)) {
      try { fs.unlinkSync(oldPath); } catch (e) {}
    }
    console.log(`[mcpd] Binary replaced: ${installedBinary}`);
    return true;
  } catch (e) {
    console.warn(`[mcpd] Failed to replace binary: ${e.message}`);
    return false;
  }
}

// Start daemon with the new binary
function startNewDaemon() {
  const installedBinary = findInstalledBinary();
  if (!installedBinary) return;

  console.log('[mcpd] Starting new daemon...');
  try {
    if (platform === 'win32') {
      // Use cmd /c start to detach the process
      const result = spawn('cmd', ['/c', 'start', '""', installedBinary, 'daemon', 'start'], {
        detached: true,
        stdio: 'ignore',
        windowsHide: true
      });
      result.unref();
    } else {
      const result = spawn(installedBinary, ['daemon', 'start'], {
        detached: true,
        stdio: 'ignore'
      });
      result.unref();
    }
    // Wait briefly to confirm it started
    setTimeout(() => {
      if (isDaemonRunning()) {
        console.log('[mcpd] New daemon started successfully!');
      } else {
        console.log('[mcpd] New daemon starting... (check http://localhost:18423/)');
      }
    }, 2000);
  } catch (e) {
    console.warn(`[mcpd] Could not start new daemon: ${e.message}`);
  }
}

// File mappings: source (relative to npm pkg) -> target (relative to home)
const files = [
  { src: 'examples/mcpd.yml', dst: '.mcpd/mcpd.yml' },
  { src: 'examples/mcpserver.json', dst: '.mcpserver.json' },  // Note: this goes in HOME not .mcpd
  { src: 'skills/mcpd/SKILL.md', dst: '.agents/skills/mcpd/SKILL.md' },
];

// Directories to create
const dirs = [
  '.mcpd',
  '.mcpd/logs',
  '.mcpd/cache',
  '.agents/skills/mcpd',
];

function copyFile(srcRel, dstRel) {
  const src = path.join(srcDir, srcRel);
  // Special handling for mcpserver.json - it goes in HOME
  let dst;
  if (dstRel === '.mcpserver.json') {
    dst = path.join(home, '.mcpserver.json');
  } else {
    dst = path.join(home, dstRel);
  }

  if (!fs.existsSync(src)) return;
  if (fs.existsSync(dst)) {
    console.log(`[mcpd] Skipped (exists): ${path.basename(dst)}`);
    return;
  }

  const dir = path.dirname(dst);
  fs.mkdirSync(dir, { recursive: true });
  fs.copyFileSync(src, dst);
  console.log(`[mcpd] Created: ${path.basename(dst)}`);
}

function createDesktopShortcut() {
  if (platform === 'win32') {
    const shortcutPath = path.join(home, 'Desktop', 'mcpd Manager.url');
    if (fs.existsSync(shortcutPath)) return;
    const content = `[InternetShortcut]
URL=http://localhost:18423/
IconFile=shell32.dll
IconIndex=13
`;
    try {
      fs.writeFileSync(shortcutPath, content, 'utf8');
      console.log('[mcpd] Created: Desktop shortcut');
    } catch (e) {}
  }
}

async function main() {
  const wasRunning = isDaemonRunning();

  if (wasRunning) {
    console.log('[mcpd] Detected running daemon, stopping it first...');
    await stopDaemonGracefully();

    // If still running, force kill
    if (isDaemonRunning()) {
      console.log('[mcpd] Force killing daemon...');
      forceKillDaemon();
      await new Promise(r => setTimeout(r, 1000));
    }
  }

  // Replace the installed binary
  const replaced = replaceInstalledBinary();

  // Copy config files
  for (const dir of dirs) {
    fs.mkdirSync(path.join(home, dir), { recursive: true });
  }
  for (const file of files) {
    copyFile(file.src, file.dst);
  }
  createDesktopShortcut();

  console.log('[mcpd] ');
  console.log('[mcpd] ============================================');
  console.log('[mcpd]  Installation complete!');
  console.log('[mcpd] ============================================');

  if (wasRunning) {
    console.log('[mcpd] ');
    console.log('[mcpd] Old daemon was running, restarting with new version...');
    startNewDaemon();
  } else {
    console.log('[mcpd] ');
    console.log('[mcpd] Quick start:');
    console.log('[mcpd]   1. Run: mcpd up');
    console.log('[mcpd]   2. Browser opens automatically');
    console.log('[mcpd]   3. Or open: http://localhost:18423/');
  }
}

main().catch(err => {
  console.warn('[mcpd] Setup warning:', err.message);
  process.exit(0);
});
