import fs from 'node:fs'
import path from 'node:path'

const root = process.cwd()
const ignoredDirs = new Set(['.git', 'node_modules', 'dist', '.next', 'coverage', '.turbo'])
const files = []

function walk(dir) {
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
    if (ignoredDirs.has(entry.name)) continue
    const p = path.join(dir, entry.name)
    if (entry.isDirectory()) walk(p)
    else files.push(p)
  }
}

walk(root)

const findings = []
const authTokenStorage = /localStorage\.(?:setItem|getItem|removeItem)\(\s*(?:['"](?:employee_token|admin_token|renter_token|employee_session|admin_session|renter_session)['"]|[A-Z0-9_]*TOKEN[A-Z0-9_]*)|document\.cookie\s*=\s*['"](?:employee_token|admin_token|renter_token|employee_session|admin_session|renter_session)=/i
const rawWebhookStringify = /JSON\.stringify\(req\.body\)/i
const secretAssignment = /^(JWT_SECRET|DATABASE_URL|POSTGRES_PASSWORD|SMTP_PASSWORD|REGISTRY_PASSWORD|REGISTRY_HTTP_SECRET|AMANPAY_WEBHOOK_SECRET|PAYPAL_WEBHOOK_SECRET|CLERK_SECRET_KEY|RESEND_API_KEY|MAIL_PASSWORD|FIREBASE_PRIVATE_KEY|TWILIO_AUTH_TOKEN|PAYPAL_CLIENT_SECRET|AMANPAY_SECRET_KEY|CLOUDINARY_API_SECRET|ADMIN_SEED_PASSWORD)\s*=\s*(.+)$/i

function isTestPath(rel) {
  return rel.includes('/test/') || rel.includes('/tests/') || /\.(test|spec)\.[tj]sx?$/.test(rel)
}

function isEnvLike(rel) {
  const base = path.basename(rel)
  return base === '.env' || base.startsWith('.env') || base.endsWith('.env')
}

function looksPlaceholder(value) {
  const v = value.trim().replace(/^['"]|['"]$/g, '')
  if (!v || /^\$\{?[A-Z0-9_]+\}?$/i.test(v)) return true
  if (/replace-with|placeholder|example|your-|your_|dummy|changeme|change-me|test-secret|localhost|127\.0\.0\.1/i.test(v)) return true
  if (/^postgresql:\/\/[^:]+:replace-with-/i.test(v)) return true
  return false
}

for (const file of files) {
  const rel = path.relative(root, file)
  if (rel.startsWith('.claude/') || rel === '.gitlab-ci.yml' || isTestPath(rel)) continue
  if (!/\.(ts|tsx|js|jsx|json|env|example|yml|yaml|toml|md|prisma|sql)$/.test(rel) && !path.basename(rel).startsWith('.env')) continue

  let text
  try { text = fs.readFileSync(file, 'utf8') } catch { continue }
  if (text.includes('\u0000')) continue
  const lines = text.split(/\r?\n/)

  for (let i = 0; i < lines.length; i += 1) {
    const line = lines[i]
    if (authTokenStorage.test(line)) {
      findings.push(`${rel}:${i + 1}: script-readable auth token storage`)
    }
    if (rel.includes('/webhooks/') || rel.includes('payment.routes') || rel.includes('subscription.routes')) {
      if (rawWebhookStringify.test(line)) findings.push(`${rel}:${i + 1}: webhook signature code must use raw body`)
    }
    if (isEnvLike(rel)) {
      const match = line.match(secretAssignment)
      if (match && !looksPlaceholder(match[2])) {
        findings.push(`${rel}:${i + 1}: possible committed secret`)        
      }
    }
  }
}

if (findings.length) {
  console.error('Security static check failed:')
  for (const finding of findings) console.error(`- ${finding}`)
  process.exit(1)
}

console.log('Security static check passed')
