import { isIP } from 'node:net'
import { DatabaseSync } from 'node:sqlite'

const [command, rawIp, rawLimit, ...noteParts] = process.argv.slice(2)
const database = new DatabaseSync('data/game.db')

function normalizeIp(value) {
  const address = String(value ?? '').trim()
  if (address.startsWith('::ffff:') && isIP(address.slice(7)) === 4) {
    return address.slice(7)
  }
  return address
}

function requireIp(value) {
  const address = normalizeIp(value)
  if (!isIP(address)) {
    throw new Error('Provide a valid IPv4 or IPv6 address.')
  }
  return address
}

try {
  if (command === 'set') {
    const ip = requireIp(rawIp)
    const maxAccounts = Number(rawLimit)
    if (!Number.isInteger(maxAccounts) || maxAccounts < 2 || maxAccounts > 100) {
      throw new Error('The allowed account count must be an integer from 2 to 100.')
    }
    const note = noteParts.join(' ').slice(0, 200)
    database.prepare(`
      INSERT INTO account_ip_allowances
        (ip_address, max_accounts, note, updated_at)
      VALUES (?, ?, ?, CURRENT_TIMESTAMP)
      ON CONFLICT(ip_address) DO UPDATE SET
        max_accounts = excluded.max_accounts,
        note = excluded.note,
        updated_at = CURRENT_TIMESTAMP
    `).run(ip, maxAccounts, note)
    console.log(`${ip} may create up to ${maxAccounts} accounts${note ? ` (${note})` : ''}.`)
  } else if (command === 'remove') {
    const ip = requireIp(rawIp)
    const result = database.prepare(`
      DELETE FROM account_ip_allowances WHERE ip_address = ?
    `).run(ip)
    console.log(
      result.changes
        ? `${ip} returned to the default one-account limit.`
        : `${ip} had no custom allowance.`,
    )
  } else if (command === 'list') {
    const rows = database.prepare(`
      SELECT
        account_ip_allowances.ip_address AS ip,
        account_ip_allowances.max_accounts AS maxAccounts,
        account_ip_allowances.note,
        account_ip_allowances.updated_at AS updatedAt,
        COUNT(accounts.id) AS existingAccounts
      FROM account_ip_allowances
      LEFT JOIN accounts
        ON accounts.created_ip = account_ip_allowances.ip_address
      GROUP BY account_ip_allowances.ip_address
      ORDER BY account_ip_allowances.updated_at DESC
    `).all()
    console.table(rows)
  } else {
    console.log('Usage:')
    console.log('  npm run accounts:ip -- set <ip> <max-accounts> [note]')
    console.log('  npm run accounts:ip -- remove <ip>')
    console.log('  npm run accounts:ip -- list')
    process.exitCode = command ? 1 : 0
  }
} catch (error) {
  console.error(error instanceof Error ? error.message : error)
  process.exitCode = 1
} finally {
  database.close()
}
