import { writeFileSync } from 'node:fs'

const SENSITIVE_ARGS = ['adminToken', 'telegramBotToken', 'webhookSharedSecret']

const args = parseArgs(process.argv.slice(2))
if (args.help) {
  process.stdout.write(usage())
  process.exit(0)
}

try {
  validateArgs(args)
} catch (error) {
  process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n\n${usage()}`)
  process.exit(1)
}

const output = args.output || ''
const env = [
  '# Generated by scripts/standalone-gateway-setup.mjs.',
  '# Keep this file private and chmod 0600.',
  'OPEN_COWORK_STANDALONE_GATEWAY_DATABASE_URL=postgres://open_cowork:replace-with-password@127.0.0.1:5432/open_cowork_gateway',
  `OPEN_COWORK_STANDALONE_GATEWAY_ADMIN_TOKEN=${args.adminToken || 'replace-with-random-admin-token'}`,
  `OPEN_COWORK_STANDALONE_GATEWAY_OPENCODE_URL=${args.opencodeUrl || 'http://127.0.0.1:4096'}`,
  'OPEN_COWORK_STANDALONE_GATEWAY_HOST=127.0.0.1',
  'OPEN_COWORK_STANDALONE_GATEWAY_PORT=8795',
  'OPEN_COWORK_STANDALONE_GATEWAY_TRUST_PROXY_HEADERS=false',
  'OPEN_COWORK_STANDALONE_GATEWAY_TRUSTED_PROXY_CIDRS=',
  'OPEN_COWORK_STANDALONE_GATEWAY_DEPLOYMENT_MODE=solo',
  'OPEN_COWORK_STANDALONE_GATEWAY_RETENTION_SESSION_DAYS=90',
  'OPEN_COWORK_STANDALONE_GATEWAY_RETENTION_ARTIFACT_DAYS=30',
  'OPEN_COWORK_STANDALONE_GATEWAY_RETENTION_AUDIT_DAYS=365',
  `OPEN_COWORK_STANDALONE_GATEWAY_TELEGRAM_BOT_TOKEN=${args.telegramBotToken || 'replace-with-telegram-bot-token'}`,
  'OPEN_COWORK_STANDALONE_GATEWAY_TELEGRAM_PROVIDER_ID=telegram',
  'OPEN_COWORK_STANDALONE_GATEWAY_TELEGRAM_CHANNEL_BINDING_ID=telegram',
  args.webhookSharedSecret ? `OPEN_COWORK_STANDALONE_GATEWAY_WEBHOOK_SHARED_SECRET=${args.webhookSharedSecret}` : null,
].filter(Boolean).join('\n') + '\n'

const nextSteps = [
  '',
  'Next steps:',
  '  pnpm build:standalone-gateway',
  '  pnpm --filter @open-cowork/standalone-gateway doctor',
  '  pnpm deploy:standalone-gateway:smoke',
  '  pnpm deploy:standalone-gateway:validate',
].join('\n') + '\n'

if (args.print || !output) {
  process.stdout.write(env)
} else {
  writeFileSync(output, env, { mode: 0o600 })
  process.stdout.write(`Wrote ${output} with mode 0600.${nextSteps}`)
}

function parseArgs(argv) {
  const parsed = {}
  for (let index = 0; index < argv.length; index += 1) {
    const arg = argv[index]
    if (arg === '--print') parsed.print = true
    else if (arg === '--allow-secret-print') parsed.allowSecretPrint = true
    else if (arg === '--help' || arg === '-h') parsed.help = true
    else if (arg.startsWith('--')) {
      const key = arg.slice(2).replace(/-([a-z])/g, (_, char) => char.toUpperCase())
      parsed[key] = argv[index + 1] || ''
      index += 1
    }
  }
  return parsed
}

function validateArgs(parsed) {
  if ((parsed.print || !parsed.output) && !parsed.allowSecretPrint) {
    const secretArgs = SENSITIVE_ARGS.filter((key) => parsed[key])
    if (secretArgs.length > 0) {
      throw new Error(`Refusing to print secret arguments to stdout: ${secretArgs.map((key) => `--${key.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`)}`).join(', ')}. Use --output or --allow-secret-print.`)
    }
  }
  if (parsed.output && !parsed.adminToken) {
    throw new Error('--admin-token is required when writing a deployable env file.')
  }
  if (parsed.output && !parsed.telegramBotToken) {
    throw new Error('--telegram-bot-token is required when writing a deployable env file.')
  }
  const opencodeUrl = parsed.opencodeUrl || 'http://127.0.0.1:4096'
  assertPrivateOpencodeUrl(opencodeUrl)
}

function assertPrivateOpencodeUrl(value) {
  let url
  try {
    url = new URL(value)
  } catch {
    throw new Error('--opencode-url must be a valid URL.')
  }
  if (!['http:', 'https:'].includes(url.protocol)) {
    throw new Error('--opencode-url must use http or https.')
  }
  const host = url.hostname.toLowerCase()
  const privateHost = host === 'localhost'
    || host === '127.0.0.1'
    || host === '::1'
    || host === '[::1]'
    || host.startsWith('10.')
    || host.startsWith('192.168.')
    || /^172\.(1[6-9]|2\d|3[0-1])\./.test(host)
  if (!privateHost) {
    throw new Error('--opencode-url must point at loopback or private network OpenCode. Do not expose OpenCode publicly.')
  }
}

function usage() {
  return `Usage: pnpm standalone-gateway:setup -- [options]

Generates a Standalone Gateway env file for the gateway-only topology.
The script refuses to print provided secrets to stdout unless
--allow-secret-print is set.

Options:
  --output <path>                 Write an env file with mode 0600.
  --admin-token <token>           Operator token for dashboard, metrics, diagnostics, and delivery controls.
  --opencode-url <url>            Private OpenCode URL. Defaults to http://127.0.0.1:4096.
  --telegram-bot-token <token>    Telegram provider token.
  --webhook-shared-secret <value> Optional signed webhook ingress secret.
  --print                         Print placeholder env to stdout.
  --allow-secret-print            Permit printing provided secret args to stdout.
  --help                          Show this help.
`
}
