/**
 * Signed OAuth state (userId) to prevent tampering when OAUTH_STATE_SECRET is set.
 */

import crypto from 'crypto'
import { config } from '../config/index.mjs'

export function buildOAuthState(userId) {
  const secret = config.oauthStateSecret
  if (!secret) {
    return JSON.stringify({ userId })
  }
  const body = JSON.stringify({ userId, exp: Date.now() + 15 * 60 * 1000 })
  const sig = crypto.createHmac('sha256', secret).update(body).digest('hex')
  return Buffer.from(JSON.stringify({ b: body, s: sig })).toString('base64url')
}

export function parseOAuthState(state) {
  if (!state || typeof state !== 'string') {
    throw new Error('invalid_state')
  }
  const trimmed = state.trim()
  const secret = config.oauthStateSecret

  if (trimmed.startsWith('{')) {
    const legacy = JSON.parse(trimmed)
    if (!legacy.userId) throw new Error('invalid_state')
    if (secret) {
      throw new Error('unsigned_state_rejected')
    }
    return { userId: legacy.userId }
  }

  const raw = Buffer.from(trimmed, 'base64url').toString('utf8')
  const outer = JSON.parse(raw)
  if (!outer.b || !outer.s) throw new Error('invalid_state')
  if (!secret) throw new Error('signed_state_requires_secret')
  const expected = crypto.createHmac('sha256', secret).update(outer.b).digest('hex')
  if (outer.s !== expected) throw new Error('invalid_state_signature')
  const payload = JSON.parse(outer.b)
  if (payload.exp != null && payload.exp < Date.now()) throw new Error('state_expired')
  if (!payload.userId) throw new Error('invalid_state')
  return { userId: payload.userId }
}
