/**
 * momo-prod-guard.js — PreToolUse Hook
 *
 * bypassPermissions: true 的安全防線。
 * 替代人工確認對話框，自動攔截所有對正式環境的破壞性操作。
 *
 * 防護範圍（momo 專屬）：
 *   1. SSH 跳板到 192.168.0.x — 阻擋破壞性 docker/rm 指令
 *   2. docker rm/down/prune — 必須確認是否針對 momo-db
 *   3. git push --force — 阻擋強推 main
 *   4. Gitea CI/CD 直接觸發 — 稽核記錄
 *   5. --remove-orphans — 永遠阻擋（ADR-011）
 */

const { spawnSync } = require('child_process');
const fs = require('fs');
const os = require('os');
const path = require('path');

let d = '';
process.stdin.on('data', c => d += c);
process.stdin.on('end', () => {
  try {
    const input = JSON.parse(d);
    const cmd = String(input.tool_input?.command || '');
    if (!cmd.trim()) { process.stdout.write(d); return; }

    const logPath = path.join(os.homedir(), '.claude', 'momo-prod-guard.log');
    const ts = new Date().toISOString();

    function block(reason) {
      const msg = `[momo-prod-guard] BLOCKED: ${reason}\n指令: ${cmd.substring(0, 120)}\n`;
      process.stderr.write(msg);
      fs.appendFileSync(logPath, `[${ts}] BLOCKED | ${reason} | ${cmd.substring(0, 200)}\n`);
      process.exit(2);
    }

    function warn(reason) {
      process.stderr.write(`[momo-prod-guard] WARNING: ${reason}\n`);
      fs.appendFileSync(logPath, `[${ts}] WARN | ${reason} | ${cmd.substring(0, 200)}\n`);
    }

    // ─── 規則 1：永遠阻擋 --remove-orphans（ADR-011：會刪 momo-db）───
    if (/--remove-orphans/.test(cmd)) {
      block('--remove-orphans 已被 ADR-011 永久停用，會刪除 momo-db 容器');
    }

    // ─── 規則 2：阻擋 force push 到 main（任何形式）───
    if (/git\s+push.*(--force|-f\b|--force-with-lease).*(main|master)/.test(cmd) ||
        /git\s+push.*main.*(--force|-f\b|--force-with-lease)/.test(cmd)) {
      block('force push 到 main 已被封鎖，請改用 PR 流程');
    }

    // ─── 規則 3：SSH 到生產主機的破壞性指令 ───
    const isSSHtoProd = /ssh.*(192\.168\.0\.(110|188)|wooo@|ollama@)/.test(cmd);
    if (isSSHtoProd) {
      // 3a. docker rm / docker rmi（容器/映像刪除）
      if (/docker\s+rm\b/.test(cmd)) {
        if (/momo-db|momo-postgres/.test(cmd)) {
          block('偵測到刪除 momo-db 容器的指令，資料庫保護啟動');
        }
        warn('遠端 docker rm 操作，已記錄稽核日誌');
      }

      // 3b. docker compose down（含 -v 清 volume）
      if (/docker\s+compose\s+down/.test(cmd)) {
        if (/-v\b|--volumes/.test(cmd)) {
          block('docker compose down -v 會清除所有 volume，包含資料庫資料，已阻擋');
        }
        warn('docker compose down（無 -v）遠端執行，已記錄');
      }

      // 3c. docker system prune
      if (/docker\s+(system\s+prune|volume\s+prune|image\s+prune)/.test(cmd)) {
        if (/-f\b|--force/.test(cmd) && /system\s+prune/.test(cmd)) {
          block('docker system prune -f 在生產主機上需要人工確認，已阻擋');
        }
        warn('docker prune 類指令，已記錄稽核日誌');
      }

      // 3e. momo-db / momo-postgres 細粒度政策（SQL / env / dump / cp）
      //     規則：read-only SELECT / EXPLAIN / SHOW / \d* 放行
      //           寫入 SQL（INSERT/UPDATE/DELETE/DROP/TRUNCATE/ALTER/CREATE/GRANT/REVOKE）一律阻擋
      //           env / printenv 一律阻擋（避免洩漏 DATABASE_URL 等敏感）
      //           pg_dump / pg_dumpall 一律阻擋（資料外洩防線）
      //           docker cp momo-db:* / momo-postgres:* 一律阻擋（繞過 SQL 直接搬檔）
      const isDbExec = /docker\s+exec\s+[^|;&]*\b(momo-db|momo-postgres)\b/.test(cmd);
      const isDbCp   = /docker\s+cp\s+[^|;&]*\b(momo-db|momo-postgres):/i.test(cmd);

      if (isDbCp) {
        block('docker cp momo-db/momo-postgres 已阻擋（資料外洩防線，請走 SQL 查詢）');
      }

      if (/\bpg_dump(all)?\b/i.test(cmd)) {
        block('pg_dump / pg_dumpall 已阻擋（資料外洩防線；備份請走每日 daily_backup 排程）');
      }

      // psql -f / 重定向 / heredoc：hook 看不到 SQL 內容 → 一律擋
      if (isDbExec && /\bpsql\b[^|;&]*(\s-f\s+\S+|\s+<\s+\S+\.sql|<<-?\s*['"]?\w+)/i.test(cmd)) {
        block('momo-db psql 透過 -f / heredoc / 重定向載入 SQL，hook 無法靜態檢驗，已阻擋');
      }

      // alias / function 包裝 docker exec：警告
      if (isDbExec && /(alias|function)\s+\w+\s*=?[^|;&]*docker\s+exec[^|;&]*momo-db/i.test(cmd)) {
        warn('偵測到 alias/function 包裝 docker exec momo-db，後續呼叫可能繞過 SQL 檢查');
      }

      if (isDbExec) {
        // env / printenv：一律擋（排除 env VAR=value 的賦值用法）
        if (/\b(env|printenv)\b(?!\s+\w+=)/.test(cmd) && !/\bgrep\b.*\b(POSTGRES_DB|POSTGRES_USER)\b/.test(cmd)) {
          block('docker exec momo-db env/printenv 已阻擋（避免洩漏 DATABASE_URL/密碼）');
        }

        // /run/secrets, /proc/*/environ：擋
        if (/\/(run\/secrets|proc\/[\d\w*]+\/environ)/.test(cmd)) {
          block('docker exec momo-db 讀取 /run/secrets 或 /proc/*/environ 已阻擋');
        }

        // PG 內建檔案讀寫 / COPY FROM PROGRAM
        if (/\b(pg_read_file|pg_read_binary_file|lo_export|lo_import)\b/i.test(cmd) ||
            /\bCOPY\b[\s\S]*?\bFROM\s+PROGRAM\b/i.test(cmd)) {
          block('momo-db PG 檔案系統函式 / COPY FROM PROGRAM 已阻擋');
        }

        // 寫入類 SQL（含 VACUUM FULL / REINDEX / REFRESH MATERIALIZED）
        const writeSqlRe = /\b(INSERT\s+INTO|UPDATE\s+\w+\s+SET|DELETE\s+FROM|DROP\s+(TABLE|DATABASE|SCHEMA|INDEX|VIEW)|TRUNCATE|ALTER\s+(TABLE|DATABASE|SCHEMA|ROLE|USER)|CREATE\s+(TABLE|DATABASE|SCHEMA|ROLE|USER|INDEX)|GRANT\b|REVOKE\b|VACUUM\s+FULL|REINDEX|REFRESH\s+MATERIALIZED|CLUSTER)\b/i;
        if (writeSqlRe.test(cmd)) {
          block('momo-db 寫入類 SQL 已阻擋（INSERT/UPDATE/DELETE/DROP/TRUNCATE/ALTER/CREATE/GRANT/REVOKE/VACUUM FULL）');
        }

        // psql -c：白/黑名單雙閘 + multi-statement + writable CTE
        const psqlCmdMatch = cmd.match(/psql[^|]*\s(?:-c|--command(?:=|\s+))\s*(['"])([\s\S]+?)\1/);
        if (psqlCmdMatch) {
          const sql = psqlCmdMatch[2].trim();
          // writable CTE：WITH ... DELETE/INSERT/UPDATE
          if (/^\s*WITH\b/i.test(sql) && /\b(DELETE|INSERT|UPDATE)\b/i.test(sql)) {
            block('momo-db psql writable CTE（WITH ... DELETE/INSERT/UPDATE）已阻擋');
          }
          // multi-statement：; 後還有非空白非註解內容（去掉 -- 與 /* */ 後判斷）
          const stripped = sql.replace(/--[^\n]*/g, '').replace(/\/\*[\s\S]*?\*\//g, '');
          if (/;\s*\S/.test(stripped)) {
            block('momo-db psql 多語句（; 後接內容）已阻擋，請拆成單句');
          }
          // 白名單 prefix（不收 WITH，避免 writable CTE 漏網）
          const isReadOnly = /^\s*(SELECT|EXPLAIN|SHOW|VALUES|TABLE\s+\w|\\d|\\l|\\dt|\\du|\\df|\\?)\b/i.test(sql);
          if (!isReadOnly) {
            block(`momo-db psql -c 非 read-only SQL 已阻擋: ${sql.substring(0, 80)}`);
          }
        }
      }

      // 3d. 稽核所有 SSH 生產指令
      fs.appendFileSync(logPath, `[${ts}] SSH-PROD | ${cmd.substring(0, 300)}\n`);
    }

    // ─── 規則 4：直接 commit 到 main（本機）───
    try {
      const branch = spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'],
        { encoding: 'utf8', timeout: 3000 }).stdout.trim();
      if (branch === 'main' && /git\s+commit\b/.test(cmd) && !/--amend.*--no-edit/.test(cmd)) {
        block(`你在 main 分支上直接 commit，請切到 feature branch：git checkout -b feat/your-name`);
      }
    } catch (e) {
      process.stderr.write(`[momo-prod-guard] hook internal error: ${e.message}\n`);
      process.exit(1);  // 防護 hook 崩潰時，保守阻擋操作
    }

    // ─── 規則 5：Telegram API 直接呼叫（稽核）───
    if (/api\.telegram\.org|sendMessage|sendPhoto|sendDocument/.test(cmd)) {
      warn('直接呼叫 Telegram API，已記錄稽核日誌');
      fs.appendFileSync(logPath, `[${ts}] TELEGRAM-API | ${cmd.substring(0, 200)}\n`);
    }

  } catch (e) {
    process.stderr.write(`[momo-prod-guard] hook internal error: ${e.message}\n`);
    process.exit(1);  // 防護 hook 崩潰時，保守起見阻擋操作
  }
  process.stdout.write(d);
});
