import crypto from 'node:crypto'

import { runtimeConfig } from '../../config/runtime.js'
import type { WorkerUserRow } from '../../repositories/worker-platform/index.js'
import { createHttpError } from '../../utils/http.js'
import { addHours, nowIso } from '../../utils/time.js'
import { normalizeSessionVersion } from './worker-normalizers.js'

export function createWorkerSessionToken(worker: WorkerUserRow) {
  const issuedAt = nowIso()
  const expiresAt = addHours(issuedAt, Number(runtimeConfig.admin?.sessionTtlHours || 12))
  const payload = {
    typ: 'worker',
    sid: crypto.randomBytes(12).toString('hex'),
    uid: Number(worker.id),
    usr: worker.username,
    status: worker.status,
    ver: normalizeSessionVersion(worker.session_version),
    iat: issuedAt,
    exp: expiresAt,
  }
  const encodedPayload = Buffer.from(JSON.stringify(payload)).toString('base64url')
  return {
    sessionId: payload.sid,
    token: `${encodedPayload}.${signWorkerPayload(encodedPayload)}`,
    expiresAt,
  }
}

export function ensureWorkerAuthConfigured() {
  if (String(runtimeConfig.admin?.sessionSecret || '').trim()) return

  throw createHttpError('接单登录态签名密钥未配置，请设置 ADMIN_SESSION_SECRET', {
    statusCode: 503,
    errorCode: 'worker_auth_not_configured',
  })
}

export function hashWorkerPassword(password: string): string {
  const salt = crypto.randomBytes(16).toString('hex')
  const derived = crypto.scryptSync(password, salt, 64).toString('hex')
  return `scrypt$${salt}$${derived}`
}

export function verifyWorkerPassword(password: string, storedHash: string): boolean {
  const [algorithm, salt, expectedHash] = String(storedHash || '').split('$')
  if (algorithm !== 'scrypt' || !salt || !expectedHash) return false
  return safeCompare(crypto.scryptSync(password, salt, 64).toString('hex'), expectedHash)
}

export function signWorkerPayload(encodedPayload: string): string {
  return crypto
    .createHmac('sha256', String(runtimeConfig.admin?.sessionSecret || ''))
    .update(`worker:${encodedPayload}`)
    .digest('base64url')
}

export function safeCompare(input: unknown, expected: unknown): boolean {
  const left = Buffer.from(String(input || ''), 'utf8')
  const right = Buffer.from(String(expected || ''), 'utf8')
  if (left.length !== right.length) return false
  return crypto.timingSafeEqual(left, right)
}
