package com.correx.core.toolintent.rules

/**
 * Pure, stateless host allow-list matching for network egress. The effective allow-list is the
 * union of the static `networkAllowedHosts` and any hosts granted to the active session (see
 * [com.correx.core.events.events.EgressHostsGrantedEvent]): a host is allowed if it matches the
 * static set OR the session set. Matching honours the exact-or-suffix semantics
 * [com.correx.core.toolintent.rules.NetworkHostRule] uses — a configured "example.com" covers
 * "api.example.com" — and never narrows it; the session set can only widen what is allowed.
 *
 * An empty union (no static and no session hosts) means "no allow-list configured", which the
 * caller treats as allow-all, mirroring the rule's existing behaviour.
 */
object EgressAllowlist {

    /**
     * True if [host] is permitted by the union of [staticHosts] and [sessionHosts]. Both sets are
     * normalised to lower-case; [host] is matched case-insensitively. An empty union allows any host.
     */
    fun isAllowed(host: String, staticHosts: Set<String>, sessionHosts: Set<String>): Boolean {
        val target = host.lowercase()
        val union = staticHosts.asSequence() + sessionHosts.asSequence()
        var sawAny = false
        for (allowed in union) {
            sawAny = true
            val a = allowed.lowercase()
            if (target == a || target.endsWith(".$a")) return true
        }
        // No allow-list configured at all → allow-all (matches NetworkHostRule's empty-list behaviour).
        return !sawAny
    }
}
