import { createHash, createHmac } from "node:crypto"

import { secrets } from "../utils/secrets"

type PushServerDevicePlatform = "web" | "ios" | "android"

export type RegisterPushServerDeviceInput = {
    localDeviceId: string
    platform: PushServerDevicePlatform
    providerToken?: string
    subscription?: Record<string, unknown>
    meta?: Record<string, unknown>
}

export type RegisterPushServerDeviceResult = {
    centralDeviceId: string
    status: string
}

export type SendPushServerMessageInput = {
    idempotencyKey: string
    devices: string[]
    priority?: "normal" | "high"
    ttlSeconds?: number
    collapseKey?: string
    notification?: {
        title?: string
        body?: string
    }
    data?: Record<string, unknown>
}

function configured() {
    return Boolean(secrets.PUSH_SERVER_URL && secrets.PUSH_SERVER_INSTANCE_ID && secrets.PUSH_SERVER_SECRET)
}

function normalizeBaseUrl() {
    return String(secrets.PUSH_SERVER_URL || "").replace(/\/+$/, "")
}

function bodyHash(body: string) {
    return createHash("sha256").update(body).digest("hex")
}

function signature(method: string, path: string, timestamp: string, body: string) {
    const canonical = [
        method.toUpperCase(),
        path,
        timestamp,
        bodyHash(body),
        secrets.PUSH_SERVER_INSTANCE_ID,
    ].join("\n")

    return createHmac("sha256", secrets.PUSH_SERVER_SECRET).update(canonical).digest("hex")
}

async function requestPushServer<T>(method: "POST" | "DELETE", path: string, payload?: unknown): Promise<T> {
    if (!configured()) {
        throw new Error("Zentraler Push-Server ist nicht konfiguriert")
    }

    const body = payload === undefined ? "" : JSON.stringify(payload)
    const timestamp = new Date().toISOString()
    const response = await fetch(`${normalizeBaseUrl()}${path}`, {
        method,
        headers: {
            Accept: "application/json",
            "Content-Type": "application/json",
            "X-Fedeo-Instance-Id": secrets.PUSH_SERVER_INSTANCE_ID,
            "X-Fedeo-Timestamp": timestamp,
            "X-Fedeo-Signature": signature(method, path, timestamp, body),
        },
        body: body || undefined,
    })

    const text = await response.text()
    const data = text ? JSON.parse(text) : null

    if (!response.ok) {
        const message = data?.message || data?.error || `Push-Server Anfrage fehlgeschlagen (${response.status})`
        throw new Error(message)
    }

    return data as T
}

export const pushServerClient = {
    configured,

    registerDevice(input: RegisterPushServerDeviceInput) {
        return requestPushServer<RegisterPushServerDeviceResult>("POST", "/v1/devices", input)
    },

    sendPush(input: SendPushServerMessageInput) {
        return requestPushServer<{ accepted: number; rejected: number; deliveryJobId: string }>("POST", "/v1/push", {
            priority: "normal",
            ttlSeconds: 3600,
            ...input,
        })
    },
}
