#ifndef MESH_VALIDATE_H
#define MESH_VALIDATE_H

#include "config.h"

// ============================================================================
// mesh_validate.h — Structural plausibility check for a deserialized
// DetectionEvent received over the air.
//
// WHY THIS EXISTS (2026-08-02)
// ----------------------------
// mesh_deserialize_event() previously validated NOTHING beyond a length check:
// it read fields at fixed offsets from whatever arrived. main.cpp dispatches on
// rx_buf[0], so ANY LoRa packet whose first byte happened to equal
// MSG_TYPE_DETECTION (0x01) or MSG_TYPE_HEALTH (0x04) was parsed as PDL
// telemetry and relayed to C2.
//
// PDL and Meshtastic share LoRa PHY parameters closely enough to hear each
// other (confirmed live: a Meshtastic node logged "fr=0x7e570101" = Gateway01,
// and PDL units in turn ingested Meshtastic frames). Because the radio's CRC
// passes on those foreign frames, they arrived looking structurally fine and
// became phantom drone contacts on the operator map:
//
//     0x577E6A04 | LORA_RELAY:Spencer01 | 20.8389635, 0
//     0xD058D812 | LORA_RELAY:Gateway01 | 10.0663296, 0
//     Spencer01  (health)                | 107.2987782, -14.9413304   <-- lat > 90
//
// Note the last one: latitude 107.3 does not exist. resolve_detection_latlon()
// clamps the DETECTION path to +/-90, but the HEALTH path
// (c2_wifi_bridge_post_relayed_health) had no clamp, so impossible coordinates
// were written into fleet position data. Clamping is the wrong remedy anyway —
// it converts garbage into a plausible-looking contact at exactly 90.0 rather
// than discarding it. An out-of-range coordinate is never salvageable.
//
// WHY NOT A MAGIC NUMBER / CHECKSUM
// ---------------------------------
// That is the stronger fix, and it should happen eventually — but it changes
// the wire format, which means every unit must be reflashed simultaneously or
// they stop hearing each other. Units are deployed and battery-powered
// (Spencer02 is wireless). These checks need NO format change, so units can be
// updated one at a time and old/new firmware interoperate throughout.
//
// DESIGN RULE: reject only the physically impossible or structurally invalid.
// A legitimate packet must NEVER be dropped. In particular lat=0/lon=0 is
// explicitly VALID — that is how a unit with no GPS and no persisted position
// correctly reports "I don't know where I am" (Spencer03 does exactly this).
// ============================================================================

// Returns true if evt could plausibly have been produced by PDL firmware.
// Pure function, no I/O, no platform dependencies — unit-testable on the host.
bool mesh_event_is_plausible(const DetectionEvent& evt);

// Fixed-point coordinate bounds (degrees * 1e7), matching DetectionEvent's
// lat_fixed/lon_fixed scale.
#define MESH_LAT_FIXED_MAX   900000000L
#define MESH_LON_FIXED_MAX  1800000000L

// Widest RSSI window any real LoRa/RF reading could occupy, in dBm. Deliberately
// generous: health packets legitimately carry rssi = 0 when no samples have been
// averaged yet (health_report.cpp:129), so 0 must remain valid.
#define MESH_RSSI_MIN_DBM   (-200)
#define MESH_RSSI_MAX_DBM   (50)

// Only these message types travel in the 33-byte DetectionEvent layout. Command,
// OTA, interop and the rest use their own formats and never reach this parser.
#define MESH_FLAGS_VALID_MASK  (FLAG_PROMOTED | FLAG_BLUE_FORCE | FLAG_SUPPRESSED)

#endif // MESH_VALIDATE_H
