/**
 * Auth helpers for the Print-Agent protocol (server/api/print-agent/*) and the
 * cookie-session admin routes (server/api/settings/print-agents/*).
 *
 * Agents authenticate with `Authorization: Bearer lspa_…` (token issued once at enrolment,
 * only its SHA-256 is stored). The browser side uses the normal LogShip session cookies.
 */
import getTokenHelper from './getTokenHelper'
import { getAgentByToken, type PrintAgentRow } from './printSpoolDb'

export const requireAgent = (event: any): PrintAgentRow => {
  const header = String(getHeader(event, 'authorization') || '')
  const token = header.startsWith('Bearer ') ? header.slice(7).trim() : ''
  const agent = token ? getAgentByToken(token) : null
  if (!agent) throw createError({ statusCode: 401, statusMessage: 'invalid or revoked agent token' })
  return agent
}

export interface AdminSession { userId: number | null; roleId: number | null; clientId: number; orgId: number }

/** Browser session (cookies + JWT). Throws 401 without a usable token. */
export const requireAdminSession = async (event: any): Promise<AdminSession> => {
  let token: string = ''
  try { token = String((await getTokenHelper(event)) || '') } catch { /* handled below */ }
  if (!token) throw createError({ statusCode: 401, statusMessage: 'not authenticated' })
  let payload: any = {}
  try { payload = JSON.parse(Buffer.from(token.split('.')[1] || '', 'base64').toString()) } catch { /* ignore */ }
  // Cookies may carry the id as "1000000", a JSON object/string or be absent (role selected in the
  // browser vs. auto-finalised login) — take the first number we can find, then the JWT claims
  // (AD_Client_ID, or the `Clients` list on a pre-role token). Never block the page on it.
  const firstInt = (v: any): number => {
    const m = /\d+/.exec(String(v ?? ''))
    return m ? Number(m[0]) : 0
  }
  const clientId = firstInt(getCookie(event, 'logship_client_id')) || firstInt(payload?.AD_Client_ID) || firstInt(payload?.Clients) || 0
  return {
    userId: firstInt(getCookie(event, 'logship_user_id')) || firstInt(payload?.AD_User_ID) || null,
    roleId: firstInt(getCookie(event, 'logship_role_id')) || firstInt(payload?.AD_Role_ID) || null,
    clientId,
    orgId: firstInt(getCookie(event, 'logship_organization_id')) || firstInt(payload?.AD_Org_ID) || 0
  }
}

// Tiny fixed-window limiter for the public enrolment endpoint (per remote IP).
const buckets = new Map<string, { n: number; ts: number }>()
export const rateLimit = (key: string, max: number, windowMs: number): boolean => {
  const now = Date.now()
  const b = buckets.get(key)
  if (!b || now - b.ts > windowMs) { buckets.set(key, { n: 1, ts: now }); return true }
  b.n++
  return b.n <= max
}

const first = (v: any): string => String(v || '').split(',')[0]?.trim() || ''

export const clientIp = (event: any): string => {
  const xf = first(getHeader(event, 'x-forwarded-for'))
  return xf || event.node?.req?.socket?.remoteAddress || 'unknown'
}

/** Public origin of this instance as seen by the agent/browser (for enrolment leaflets). */
export const instanceOrigin = (event: any): string => {
  const proto = first(getHeader(event, 'x-forwarded-proto')) || 'https'
  const host = first(getHeader(event, 'x-forwarded-host') || getHeader(event, 'host'))
  return host ? `${proto}://${host}` : ''
}
