// cogeco-checker/server.js — REST API for competitor (Cogeco) serviceability.
// targo-hub (3300) -> cogeco-checker (3302) -> cogeco.ca address checker
// Internal only, token auth, rate-limited (real browser + reCAPTCHA upstream).

const http = require('http')
const url = require('url')
const cogeco = require('./lib/cogeco-session')

const PORT = parseInt(process.env.CHECKER_PORT || '3302')
const TOKEN = process.env.CHECKER_TOKEN || ''
// Serialize checks: one real browser context at a time + a small gap so we
// don't hammer Cogeco (reCAPTCHA score protection). Concurrency=1 by design.
const MIN_GAP_MS = parseInt(process.env.CHECKER_MIN_GAP_MS || '4000')

let _chain = Promise.resolve()
let _lastRun = 0
function enqueue (fn) {
  const run = _chain.then(async () => {
    const wait = Math.max(0, MIN_GAP_MS - (Date.now() - _lastRun))
    if (wait) await new Promise(r => setTimeout(r, wait))
    try { return await fn() } finally { _lastRun = Date.now() }
  })
  // Keep the chain alive even if one job throws.
  _chain = run.catch(() => {})
  return run
}

function json (res, data, status = 200) {
  res.writeHead(status, { 'Content-Type': 'application/json' })
  res.end(JSON.stringify(data))
}
function err (res, msg, status = 400) { json(res, { error: msg }, status) }

function parseBody (req) {
  return new Promise((resolve, reject) => {
    let body = ''
    req.on('data', c => { body += c })
    req.on('end', () => { try { resolve(body ? JSON.parse(body) : {}) } catch { reject(new Error('Invalid JSON')) } })
    req.on('error', reject)
  })
}

function checkAuth (req, res) {
  if (!TOKEN) return true
  if (req.headers['authorization'] === `Bearer ${TOKEN}`) return true
  err(res, 'Unauthorized', 401)
  return false
}

const server = http.createServer(async (req, res) => {
  const parsed = url.parse(req.url, true)
  const path = parsed.pathname
  const method = req.method

  res.setHeader('Access-Control-Allow-Origin', '*')
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
  res.setHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type')
  if (method === 'OPTIONS') { res.writeHead(204); res.end(); return }

  if (path === '/health' && method === 'GET') {
    return json(res, { status: 'ok', uptime: process.uptime() })
  }

  if (!checkAuth(req, res)) return

  try {
    // POST /check { address, debug? } → { available, max_download_mbps, plans, confidence }
    if (path === '/check' && method === 'POST') {
      const body = await parseBody(req)
      const address = (body.address || '').trim()
      if (!address || address.length < 5) return err(res, 'address required (min 5 chars)')
      const debug = !!body.debug
      const out = await enqueue(() => cogeco.checkAddress(address, { debug }))
      return json(res, out)
    }
    err(res, 'Not found', 404)
  } catch (e) {
    console.error('[cogeco-checker] error:', e)
    err(res, 'Internal error: ' + e.message, 500)
  }
})

server.listen(PORT, () => {
  console.log(`[cogeco-checker] listening on ${PORT}, auth ${TOKEN ? 'on' : 'OFF (dev)'}, min-gap ${MIN_GAP_MS}ms`)
})

for (const sig of ['SIGTERM', 'SIGINT']) {
  process.on(sig, async () => {
    console.log(`[cogeco-checker] ${sig}, shutting down`)
    await cogeco.shutdown()
    server.close()
    process.exit(0)
  })
}
process.on('uncaughtException', e => console.error('[cogeco-checker] uncaught:', e))
