/**
 * 数据库 SQL 约束检查。
 * 该脚本检查关键防线是否被后续重构移除，不尝试替代 EXPLAIN 和生产监控。
 */
import fs from 'node:fs'
import path from 'node:path'
import { execFileSync } from 'node:child_process'
import { fileURLToPath } from 'node:url'

const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url))
const BACKEND_ROOT = path.resolve(SCRIPT_DIR, '..')

const checks: Array<{ name: string; file: string; patterns: string[] }> = [
  {
    name: '慢查询阈值配置',
    file: path.join(BACKEND_ROOT, 'src/config/env-overrides.ts'),
    patterns: ['DATABASE_SLOW_QUERY_THRESHOLD_MS', 'slowQueryThresholdMs'],
  },
  {
    name: '慢查询日志与参数脱敏',
    file: path.join(BACKEND_ROOT, 'src/db/client.ts'),
    patterns: ['logSlowQuery', 'fingerprintSql', '参数值始终不写入日志'],
  },
  {
    name: '高频 pending 查询索引',
    file: path.join(BACKEND_ROOT, 'src/db/migrations/058_database_query_guardrails.sql'),
    patterns: [
      'idx_worker_cancel_requests_pending_worker_order',
      'idx_worker_feedbacks_pending_worker_order',
      'idx_work_order_events_order_type_id',
    ],
  },
  {
    name: '打手订单拼单查询限定当前页',
    file: path.join(BACKEND_ROOT, 'src/repositories/worker-platform/work-order-share-repo.ts'),
    patterns: ['workOrderIds: number[]', 'wos.work_order_id = ANY($2::bigint[])'],
  },
  {
    name: '数据保留清理扫描索引',
    file: path.join(BACKEND_ROOT, 'src/db/migrations/067_data_retention_indexes.sql'),
    patterns: [
      'idx_orders_updated_at',
      'idx_kuaishou_industry_vouchers_updated_at',
      'idx_task_events_created_at',
      'idx_webhook_events_created_at',
      'DROP INDEX IF EXISTS idx_work_product_match_logs_created_at',
    ],
  },
  {
    name: '打手超时事件统计索引',
    file: path.join(BACKEND_ROOT, 'src/db/migrations/068_timeout_event_worker_index.sql'),
    patterns: [
      'idx_work_order_events_timeout_worker_id',
      "payload_json->>'workerId'",
      "WHERE event_type LIKE 'timeout_%'",
    ],
  },
]

const failures: string[] = []

// 已应用的历史迁移必须保持字节不变，所有结构或数据修复都必须新增迁移文件。
try {
  const diffOutputs = [
    execFileSync('git', ['diff', '--name-status', 'HEAD', '--', 'src/db/migrations'], {
      cwd: BACKEND_ROOT,
      encoding: 'utf8',
    }),
    execFileSync('git', ['diff', '--name-status', 'HEAD^', 'HEAD', '--', 'src/db/migrations'], {
      cwd: BACKEND_ROOT,
      encoding: 'utf8',
    }),
  ]
  const changedHistoricalMigrations = diffOutputs
    .flatMap((output) => output.split('\n'))
    .map((line) => line.trim().split(/\s+/))
    .filter(([status, file]) => status && file?.endsWith('.sql') && status !== 'A')
    .map(([status, file]) => `${status} ${file}`)
  if (changedHistoricalMigrations.length > 0) {
    failures.push(`历史迁移文件不可修改: ${changedHistoricalMigrations.join(', ')}`)
  }
} catch (error) {
  failures.push(`历史迁移完整性检查失败: ${error instanceof Error ? error.message : String(error)}`)
}

for (const check of checks) {
  if (!fs.existsSync(check.file)) {
    failures.push(`${check.name}: 文件不存在 ${check.file}`)
    continue
  }
  const source = fs.readFileSync(check.file, 'utf8')
  for (const pattern of check.patterns) {
    if (!source.includes(pattern)) {
      failures.push(`${check.name}: 缺少约束 ${pattern} (${check.file})`)
    }
  }
}

if (failures.length > 0) {
  console.error('[sql-guard] SQL 约束检查失败')
  for (const failure of failures) console.error(`[sql-guard] ${failure}`)
  process.exitCode = 1
} else {
  console.info('[sql-guard] SQL 约束检查通过')
}
