package main

import (
	"crypto/sha256"
	"encoding/hex"
	"os"
	"strings"
)

// deniedCallHashes lists station callsigns not permitted to run this build,
// stored as SHA-256 hex of the base call so the calls themselves appear nowhere
// in the source or the compiled binary. Enforcement is best-effort by design —
// the call is entered by the operator and can be changed — so this only turns
// away straightforward use, not a determined one.
var deniedCallHashes = map[string]struct{}{
	"2282a88b3e5e4eebc6b8174d005bb46d32025758b7741bdcf34f2b3621c02205": {},
	"0ee09fe60817a2a4982f5e5b14a60b8dbb11cff55b3d36661213c4cbdd0933ea": {},
	"46fb61e71afb40627cb6493a6a59c9d4d0231ee3cad1a2bf3fcc4cdfce36fabc": {},
	"d1ae6212ec057f9d5c6f379fb57acedac7c94142c9d49667dc04b2016d03d1b6": {},
	"0741c9e394b42f43191899105553b47155ddc3026da12b5360701f9c181ff123": {},
	"ab4926a3a0ab76d41b5b99cd3ad0683584970c341c29427c1dfa4b3c329ce415": {},
	"9d17c9c213a6cc89c12d7520bcf21c86a0cf43d17e82e74f33f3a77cb865d28a": {},
	"94ee059335e587e501cc4bf90613e0814f00a7b08bc7c648fd865a2af6a22cc2": {},
}

// callDenied reports whether a callsign is on deniedCallHashes. The call is
// reduced to its base form (upper-cased, portable prefix/suffix dropped) the
// same way extsvc does, so F4XYZ/P matches F4XYZ.
func callDenied(call string) bool {
	base := denyBaseCall(call)
	if base == "" {
		return false
	}
	sum := sha256.Sum256([]byte(base))
	_, bad := deniedCallHashes[hex.EncodeToString(sum[:])]
	return bad
}

// denyBaseCall mirrors extsvc.baseCall: for a slashed form it returns the
// longest token (the real call), otherwise the call itself, upper-cased.
func denyBaseCall(s string) string {
	s = strings.ToUpper(strings.TrimSpace(s))
	if !strings.Contains(s, "/") {
		return s
	}
	best := ""
	for _, part := range strings.Split(s, "/") {
		if len(part) > len(best) {
			best = part
		}
	}
	return best
}

// enforceCallGate exits the process silently when any of the supplied callsigns
// is denied. Called once at startup, after the profiles are loaded: the first
// launch is where the operator enters and saves the call, so a denied build
// simply does not come back up on the next launch. No window, no message.
func enforceCallGate(calls ...string) {
	for _, c := range calls {
		if callDenied(c) {
			os.Exit(0)
		}
	}
}
