/*
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package com.runicgateway.app.core.push

import java.security.SecureRandom

/**
 * The app's own ntfy topic — the heart of the embedded-distributor design
 * (PLAN.md §11, M7 Part 2 work item 1). The app mints a **random, unguessable**
 * topic and registers its public URL (`https://<ntfy-host>/<topic>`) as the device
 * endpoint the backend POSTs tickles to; the app subscribes to the same topic's SSE
 * stream to receive them. Security rests on the topic being unguessable plus the
 * content-free tickle — a leaked topic name reveals nothing.
 */
object NtfyTopic {

    // ntfy topic names allow [A-Za-z0-9_-]; keep to that set. The "up" prefix mirrors
    // the UnifiedPush convention and makes topics recognizable in logs/relay.
    private const val ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    private const val TOPIC_LEN = 24
    private const val PREFIX = "up"

    private val secureRandom by lazy { SecureRandom() }

    /** Mint a fresh unguessable topic, e.g. "up7Qk3…" (≈143 bits of entropy). */
    fun generate(random: java.util.Random = secureRandom): String {
        val sb = StringBuilder(PREFIX.length + TOPIC_LEN)
        sb.append(PREFIX)
        repeat(TOPIC_LEN) { sb.append(ALPHABET[random.nextInt(ALPHABET.length)]) }
        return sb.toString()
    }

    /**
     * The endpoint URL the backend publishes to: `<ntfyBaseUrl>/<topic>`. [ntfyBaseUrl]
     * is the client-facing base from `/public/settings.push.ntfyUrl`; a trailing slash
     * is tolerated. Returns null for a blank base or topic.
     */
    fun endpointUrl(ntfyBaseUrl: String?, topic: String): String? {
        val base = ntfyBaseUrl?.trim()?.trimEnd('/').orEmpty()
        if (base.isEmpty() || topic.isBlank()) return null
        return "$base/$topic"
    }

    /** The SSE subscribe URL the app connects to: `<ntfyBaseUrl>/<topic>/sse`. */
    fun sseUrl(ntfyBaseUrl: String?, topic: String): String? =
        endpointUrl(ntfyBaseUrl, topic)?.let { "$it/sse" }
}
