// gstack-guardian.js — OpenCode plugin for gstack safety skills
// Integrates: /careful, /freeze, /guard
//
// Usage: Place this file in your OpenCode plugin directory
// or reference it in your OpenCode configuration.

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

// State file for freeze boundary
const FREEZE_STATE = path.join(process.env.HOME, '.gstack', 'freeze-dir.txt');

// Destructive command patterns
const DANGEROUS_PATTERNS = [
  { pattern: /rm\s+(-[a-zA-Z]*r|--recursive)/, message: 'Destructive: recursive delete (rm -r). This permanently removes files.', name: 'rm_recursive' },
  { pattern: /DROP\s+(TABLE|DATABASE)/i, message: 'Destructive: SQL DROP detected. This permanently deletes database objects.', name: 'drop_table' },
  { pattern: /\bTRUNCATE\b/i, message: 'Destructive: SQL TRUNCATE detected. This deletes all rows from a table.', name: 'truncate' },
  { pattern: /git\s+push\s+.*(-f\b|--force)/, message: 'Destructive: git force-push rewrites remote history. Other contributors may lose work.', name: 'git_force_push' },
  { pattern: /git\s+reset\s+--hard/, message: 'Destructive: git reset --hard discards all uncommitted changes.', name: 'git_reset_hard' },
  { pattern: /git\s+(checkout|restore)\s+\./, message: 'Destructive: discards all uncommitted changes in the working tree.', name: 'git_discard' },
  { pattern: /kubectl\s+delete/, message: 'Destructive: kubectl delete removes Kubernetes resources. May impact production.', name: 'kubectl_delete' },
  { pattern: /docker\s+(rm\s+-f|system\s+prune)/, message: 'Destructive: Docker force-remove or prune. May delete running containers or cached images.', name: 'docker_destructive' },
];

// Safe rm targets (build artifacts)
const SAFE_RM_TARGETS = [
  'node_modules', '.next', 'dist', '__pycache__', '.cache', 'build', '.turbo', 'coverage',
];

function isSafeRm(cmd) {
  // Check if this is rm -r targeting only safe directories
  const rmMatch = cmd.match(/rm\s+(-[a-zA-Z]+\s+)*/);
  if (!rmMatch) return false;
  
  const args = cmd.replace(/rm\s+(-[a-zA-Z]+\s+)*/, '').trim();
  const targets = args.split(/\s+/);
  
  return targets.every(target => {
    if (target.startsWith('-')) return true;
    const basename = path.basename(target);
    return SAFE_RM_TARGETS.includes(basename);
  });
}

function checkCareful(cmd) {
  // Skip if it's a safe rm
  if (/rm\s+(-[a-zA-Z]*r|--recursive)/.test(cmd) && isSafeRm(cmd)) {
    return null;
  }
  
  // Check dangerous patterns
  for (const { pattern, message, name } of DANGEROUS_PATTERNS) {
    if (pattern.test(cmd)) {
      return { message: `[careful] ${message}`, pattern: name };
    }
  }
  
  return null;
}

function checkFreeze(filePath) {
  try {
    const freezeDir = fs.readFileSync(FREEZE_STATE, 'utf-8').trim();
    if (!freezeDir) return null;
    
    const resolvedPath = path.resolve(filePath);
    const resolvedBoundary = path.resolve(freezeDir);
    
    if (!resolvedPath.startsWith(resolvedBoundary)) {
      return {
        message: `[freeze] Blocked: ${filePath} is outside the freeze boundary (${freezeDir}). Only edits within the frozen directory are allowed.`,
      };
    }
  } catch (e) {
    if (e.code !== 'ENOENT') throw e;
  }
  
  return null;
}

module.exports = async ({ project, client, $, directory, worktree }) => {
  // Read guard state
  const guardStateFile = path.join(process.env.HOME, '.gstack', 'guard-active.txt');
  
  function isGuardActive() {
    try {
      return fs.existsSync(guardStateFile);
    } catch {
      return false;
    }
  }
  
  function isCarefulActive() {
    try {
      return fs.existsSync(path.join(process.env.HOME, '.gstack', 'careful-active.txt'));
    } catch {
      return false;
    }
  }
  
  function isFreezeActive() {
    try {
      return fs.existsSync(FREEZE_STATE);
    } catch {
      return false;
    }
  }
  
  return {
    'tool.execute.before': async (input, output) => {
      const guardActive = isGuardActive();
      const carefulActive = isCarefulActive() || guardActive;
      const freezeActive = isFreezeActive() || guardActive;
      
      // === Careful: Destructive command interception ===
      if (carefulActive && input.tool === 'bash') {
        const cmd = output.args?.command || '';
        const result = checkCareful(cmd);
        if (result) {
          throw new Error(
            `⚠️  GStack Guard: Destructive command intercepted\n` +
            `Command: ${cmd}\n` +
            `Pattern: ${result.pattern}\n` +
            `Message: ${result.message}\n` +
            `To override, disable /careful or /guard first.`
          );
        }
      }
      
      // === Freeze: Edit directory restriction ===
      if (freezeActive && (input.tool === 'edit' || input.tool === 'write')) {
        const filePath = output.args?.filePath || output.args?.path || '';
        if (filePath) {
          const result = checkFreeze(filePath);
          if (result) {
            throw new Error(
              `⚠️  GStack Freeze: Edit intercepted\n` +
              result.message +
              `\nTo remove restriction, run /unfreeze.`
            );
          }
        }
      }
    },
  };
};
