import { createHmac } from 'crypto'

interface ApprovePayload {
  channels: { id: string; name: string }[]
  email: string
  exp: number
}

const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000

function getSecret(): string {
  const secret = process.env.TOKEN_SECRET
  if (!secret) throw new Error('TOKEN_SECRET env var is not set')
  return secret
}

export function createApproveToken(
  channels: { id: string; name: string }[],
  email: string,
): string {
  const payload: ApprovePayload = {
    channels,
    email,
    exp: Date.now() + SEVEN_DAYS_MS,
  }
  const data = Buffer.from(JSON.stringify(payload)).toString('base64url')
  const sig = createHmac('sha256', getSecret()).update(data).digest('hex')
  return `${data}.${sig}`
}

export function verifyApproveToken(token: string): ApprovePayload | null {
  const parts = token.split('.')
  if (parts.length !== 2) return null

  const [data, sig] = parts
  const expected = createHmac('sha256', getSecret()).update(data).digest('hex')

  // Constant-time comparison
  if (sig.length !== expected.length) return null
  let mismatch = 0
  for (let i = 0; i < sig.length; i++) {
    mismatch |= sig.charCodeAt(i) ^ expected.charCodeAt(i)
  }
  if (mismatch !== 0) return null

  try {
    const payload: ApprovePayload = JSON.parse(
      Buffer.from(data, 'base64url').toString('utf-8'),
    )

    if (!payload.exp || !payload.channels || !payload.email) return null
    if (Date.now() > payload.exp) return null

    return payload
  } catch {
    return null
  }
}
