/**
 * MWT / JWT decode — HS256 verification, cross-language parity with
 * cores/mizan-python/src/mizan_core/mwt.py.
 *
 * Returns null on ANY failure (bad signature, expired, future nbf, wrong
 * aud, malformed). Never throws.
 */

import { createHmac, timingSafeEqual } from 'crypto'
import type { Identity } from './identity'

export interface MwtPayload {
    sub: string
    staff: boolean
    super: boolean
    pkey: string
    kid: string
    aud: string
    iat: number
    exp: number
}

function base64urlDecode(input: string): Buffer | null {
    if (!/^[A-Za-z0-9_-]*$/.test(input)) return null
    return Buffer.from(input, 'base64url')
}

function constantTimeEqual(a: Buffer, b: Buffer): boolean {
    if (a.length !== b.length) return false
    return timingSafeEqual(a, b)
}

/**
 * Decode and validate an MWT (HS256 JWT with Mizan claims).
 * Returns MwtPayload on success, null on any failure.
 */
export function decodeMwt(
    token: string,
    secret: string,
    audience: string = 'mizan',
): MwtPayload | null {
    try {
        const parts = token.split('.')
        if (parts.length !== 3) return null
        const [headerB64, payloadB64, signatureB64] = parts

        const headerBytes = base64urlDecode(headerB64)
        const payloadBytes = base64urlDecode(payloadB64)
        const signatureBytes = base64urlDecode(signatureB64)
        if (!headerBytes || !payloadBytes || !signatureBytes) return null

        const header = JSON.parse(headerBytes.toString('utf-8'))
        if (header.alg !== 'HS256') return null

        // Recompute HMAC over `${headerB64}.${payloadB64}`
        const expected = createHmac('sha256', secret)
            .update(`${headerB64}.${payloadB64}`)
            .digest()
        if (!constantTimeEqual(expected, signatureBytes)) return null

        const data = JSON.parse(payloadBytes.toString('utf-8'))

        const now = Math.floor(Date.now() / 1000)
        if (typeof data.exp !== 'number' || data.exp <= now) return null
        if (data.nbf !== undefined && typeof data.nbf === 'number' && data.nbf > now) return null
        if (data.aud !== audience) return null

        const kid = typeof header.kid === 'string' ? header.kid : 'v1'

        return {
            sub: String(data.sub),
            staff: Boolean(data.staff),
            super: Boolean(data.super),
            pkey: typeof data.pkey === 'string' ? data.pkey : '',
            kid,
            aud: audience,
            iat: data.iat,
            exp: data.exp,
        }
    } catch {
        return null
    }
}

/**
 * Decode a Bearer JWT from an Authorization header value.
 * Strips the "Bearer " prefix, then validates as an MWT.
 */
export function decodeJwtBearer(
    authHeader: string,
    secret: string,
    audience: string = 'mizan',
): MwtPayload | null {
    if (!authHeader) return null
    const prefix = 'Bearer '
    const token = authHeader.startsWith(prefix)
        ? authHeader.slice(prefix.length)
        : authHeader
    return decodeMwt(token, secret, audience)
}

/** Build an Identity from a decoded MWT payload. */
export function identityFromMwt(payload: MwtPayload): Identity {
    return {
        isAuthenticated: true,
        isStaff: payload.staff,
        isSuperuser: payload.super,
        id: Number(payload.sub),
    }
}
