#ifndef HANDSET_FINGERPRINT_H
#define HANDSET_FINGERPRINT_H

// ============================================================================
// handset_fingerprint.h — Passive handset/phone presence detection
// (WiFi probe-request + BLE advertisement metadata only — ADDITIVE).
//
// Generalizes PDL Witness's probe_fingerprint.c (which only identified
// drone-controller-app phones) into two layers:
//   1. General vendor identification for ANY nearby WiFi/BLE device, via
//      OUI (MAC vendor prefix) lookup against a curated common-vendor
//      table (Apple, Samsung, Google, etc.) — "what's in proximity," same
//      way network_id_sniffer already catalogs nearby APs.
//   2. The original drone-controller-app signature table (DJI Pilot2/Fly,
//      AutelGo, Skydio, Parrot FreeFlight, Walksnail, HDZero), preserved
//      as a specific match case within the general framework.
//
// Strictly passive metadata only:
//   - WiFi: probe-request source MAC + OUI + probed SSID + vendor-IE OUI
//   - BLE: advertisement source MAC + manufacturer-ID + local name
// No decryption, no association/pairing, no packet-content inspection
// beyond what's already broadcast in cleartext management/advertisement
// frames. Taps the EXISTING promiscuous WiFi capture (combined_promiscuous_
// cb in main.cpp) and the existing BLE passive scan (ble_odid_scanner.cpp)
// — adds no new radio duty cycle.
//
// Honest limitation: modern iOS/Android randomize the MAC address used in
// probe requests and BLE advertisements per session/rotation policy, which
// limits long-term tracking of a specific device across days — this still
// gives an accurate real-time count/vendor-mix of what's nearby right now,
// which is the stated goal, but is not a persistent per-device tracker.
// ============================================================================

#include <cstdint>
#include <cstddef>

void handset_fingerprint_init();

// Feed a raw 802.11 management frame (must be a probe-request, subtype
// 0x04). Safe to call from the promiscuous RX callback (IRAM-safe, no
// malloc, no blocking).
void handset_fingerprint_process_wifi_probe(const uint8_t* frame, size_t len, int8_t rssi);

// Feed a BLE advertisement's raw address + manufacturer-data/name fields.
// mac must be exactly 6 bytes. is_public_addr distinguishes a real, static
// BLE_ADDR_PUBLIC identity (NimBLEAddress::getType()) from a rotating
// BLE_ADDR_RANDOM address (resolvable/non-resolvable private, or static
// random) -- makes "is this device using its real address or a rotating
// one" an observable fact per device instead of an assumption.
void handset_fingerprint_process_ble_adv(const uint8_t mac[6],
                                          const uint8_t* adv_data, size_t adv_len,
                                          int8_t rssi, bool is_public_addr);

// Drone-controller-app class (same taxonomy as PDL Witness's original).
enum HandsetAppClass : uint8_t {
    HANDSET_APP_NONE = 0,
    HANDSET_APP_DJI_PILOT2,
    HANDSET_APP_DJI_FLY,
    HANDSET_APP_AUTEL_GO,
    HANDSET_APP_SKYDIO,
    HANDSET_APP_PARROT_FREEFLIGHT,
    HANDSET_APP_WALKSNAIL,
    HANDSET_APP_HDZERO,
    HANDSET_APP_IRIDIUM_GO,   // WiFi-hotspot proxy for a paired Iridium GO! unit
};

struct HandsetStats {
    uint32_t wifi_probes_seen;
    uint32_t ble_adverts_seen;
    uint16_t distinct_devices_last_60s;   // rolling presence-ring count
    uint16_t vendor_matches_total;        // OUI matched a known vendor at all
    uint16_t controller_app_matches_total; // matched a specific drone/Iridium app sig
    uint16_t camera_vendor_matches_total;  // resolved vendor is a known camera/
                                            // surveillance-equipment manufacturer
                                            // -- whitehat "unexpected camera
                                            // nearby" lead, see camera_vendor_
                                            // table in handset_fingerprint.cpp
};

void handset_fingerprint_get_stats(HandsetStats* out);

struct HandsetDeviceInfo {
    uint8_t  mac[6];
    char     vendor[16];   // "" if OUI didn't match a known vendor
    char     app_label[24]; // "" unless a controller-app signature matched
    int8_t   last_rssi;
    uint32_t last_seen_ms;
    bool     via_ble;       // true if last seen over BLE, false if WiFi probe
    bool     is_public_addr; // BLE only: true=BLE_ADDR_PUBLIC (real, static
                              // identity), false=BLE_ADDR_RANDOM (rotating).
                              // Always true for WiFi (802.11 has no random-
                              // address-type concept at this layer).
    bool     is_known_camera_vendor; // resolved OUI vendor string matched a
                              // curated list of dedicated CCTV/surveillance-
                              // camera manufacturers (Hikvision, Dahua,
                              // Reolink, etc.) -- whitehat "there is a
                              // camera's radio nearby" lead, not proof of a
                              // hidden/covert installation. See
                              // kCameraVendorSubstrings in handset_
                              // fingerprint.cpp for the exact list.
};

// Snapshot the current presence ring (devices seen in the last 60s).
// Returns the number of entries written (<= max).
size_t handset_fingerprint_list_devices(HandsetDeviceInfo* out, size_t max);

// Test-only injection points (mirrors ble_odid_scanner_test_inject /
// wifi_odid_scanner_test_inject's pattern) — run a raw frame through the
// exact same production parse path without needing a second radio.
bool handset_fingerprint_test_inject_wifi(const uint8_t* frame, size_t len, int8_t rssi);
bool handset_fingerprint_test_inject_ble(const uint8_t mac[6],
                                          const uint8_t* adv_data, size_t adv_len,
                                          int8_t rssi, bool is_public_addr = true);

#endif // HANDSET_FINGERPRINT_H
