// ignore_for_file: constant_identifier_names
import 'dart:math' as math;

/// All system-wide numeric constants for the secure-voice pipeline.
///
/// Design target:
///   modem gross rate  : 1 200 bps  (4-FSK, 600 baud, 2 bits/symbol)
///   RS(15,11) FEC net : ~880 bps
///   voice codec       : ~360 bps   (LPC, 200 ms super-frames)
///   one-way latency   : ~250 ms    (frame + processing + buffer)
abstract final class C {
  // ── Sample rate ────────────────────────────────────────────────────
  /// Must match the cellular audio path (PCM 8 kHz narrowband).
  static const int sampleRate = 8000;

  // ── 4-FSK modem ────────────────────────────────────────────────────
  /// Symbol rate in baud. 600 baud × 2 bits/symbol = 1 200 bps gross.
  static const int baudRate = 600;

  /// Samples per symbol as a float (8000 / 600 = 13.333…).
  /// The modulator uses a phase accumulator; the demodulator uses an
  /// early–late gate timing recovery loop to handle the fraction.
  static const double samplesPerSymbol = sampleRate / baudRate;

  /// 4-FSK tone frequencies (Hz). Spaced 400 Hz apart, centred in
  /// the 300–3400 Hz cellular pass-band; chosen to survive AMR-NB codec.
  ///   symbol dibit → frequency
  ///   00 → tone0   01 → tone1   10 → tone2   11 → tone3
  static const List<double> fskToneHz = [1000.0, 1400.0, 1800.0, 2200.0];

  /// Amplitude of the transmitted FSK signal (0–1 normalised).
  /// Kept below 0.7 to avoid clipping after phone mic AGC compresses it.
  static const double txAmplitude = 0.60;

  /// Preamble: alternating dibit 00/11 repeated this many times before
  /// each packet. Used by the demodulator for timing acquisition.
  static const int preambleSymbols = 24;

  /// Two-byte wire sync-word placed after preamble (0x5A, 0xA5).
  static const List<int> syncWord = [0x5A, 0xA5];

  // ── Packet layout (pre-FEC plaintext frame) ────────────────────────
  /// Bytes: [SYNC(2)] [SEQ(2)] [TYPE(1)] [LEN(1)] [PAYLOAD(11)] [CRC16(2)]
  static const int pktSyncLen    = 2;
  static const int pktSeqLen     = 2;
  static const int pktTypeLen    = 1;
  static const int pktLenLen     = 1;
  static const int pktPayloadLen = 11;   // encrypted voice frame bytes
  static const int pktCrcLen     = 2;
  static const int pktTotalBytes = pktSyncLen + pktSeqLen + pktTypeLen +
                                   pktLenLen  + pktPayloadLen + pktCrcLen; // 19 B

  /// Packet type codes.
  static const int pkTypeVoice   = 0x01;
  static const int pkTypeControl = 0x02;
  static const int pkTypeHandshake = 0x03;
  static const int pkTypePing    = 0x04;

  // ── Reed-Solomon RS(15,11) over GF(16) ────────────────────────────
  /// RS codeword length n (nibbles).
  static const int rsN = 15;
  /// RS data symbols per codeword k (nibbles).
  static const int rsK = 11;
  /// RS parity symbols per codeword (n-k).
  static const int rsParity = rsN - rsK; // 4
  /// Correction capability: t = parity/2 = 2 nibble errors per codeword.
  static const int rsT = rsParity ~/ 2;

  // ── LPC voice codec ────────────────────────────────────────────────
  /// Sub-frame size (samples). One LPC analysis frame = 20 ms at 8 kHz.
  static const int lpcSubframeSamples = 160;  // 20 ms

  /// Number of sub-frames in one super-frame (transmitted as a packet).
  static const int lpcSubframesPerSuper = 10; // 200 ms total

  /// LPC analysis order (number of predictor coefficients).
  static const int lpcOrder = 10;

  /// Minimum pitch period in samples (max fundamental ~400 Hz).
  static const int pitchMinSamples = 20;

  /// Maximum pitch period in samples (min fundamental ~50 Hz).
  static const int pitchMaxSamples = 160;

  /// Pre-emphasis coefficient. Applied as s'[n] = s[n] - alpha·s[n-1].
  static const double preEmphasis = 0.97;

  // ── AES-256-CTR ────────────────────────────────────────────────────
  /// Key length in bytes.
  static const int aesKeyBytes = 32;
  /// Nonce length in bytes (packed from session-ID + packet-seq).
  static const int aesNonceBytes = 16; // AES block size = 128 bits

  // ── PBKDF2 ─────────────────────────────────────────────────────────
  static const int pbkdf2Iterations = 100000;
  static const int pbkdf2SaltBytes  = 16;

  // ── AGC / Signal conditioning ──────────────────────────────────────
  /// Target RMS level for received signal (normalised 0–1).
  static const double agcTargetRms = 0.15;
  /// AGC attack time constant (samples). Fast attack.
  static const double agcAlpha = 0.001;

  // ── Goertzel window length (must be ≥ samplesPerSymbol) ───────────
  /// We snap to 14 integer samples which is the nearest integer above
  /// samplesPerSymbol. Timing recovery compensates for the 0.67 sample drift.
  static const int goertzelWindow = 14;

  // ── Derived constants ──────────────────────────────────────────────
  /// Pre-computed Goertzel coefficients for each FSK tone.
  /// coeff[i] = 2 · cos(2π · f_i / sampleRate)
  static final List<double> goertzelCoeff = fskToneHz
      .map((f) => 2.0 * math.cos(2.0 * math.pi * f / sampleRate))
      .toList(growable: false);
}
