//! Deterministic row generators for write-throughput benchmarking.
//!
//! Defines the workload-fixture shape designed to be shared between
//! the Rust criterion harness (`benches/postgres_write_throughput.rs`)
//! and a parallel Python timing script. Both runners build rows with
//! identical field layouts and identical, deterministic content for
//! primary keys, datetimes, and vector payloads. For the same
//! `(seed, namespace, index)` triple the emitted bytes match, so
//! per-variant throughput numbers measure the runtime differences
//! between the two SDKs and not workload differences.
//!
//! The module is intentionally always-public (no feature gate) so the
//! Python timing script and any future benchmark consumer can vendor or
//! mirror the shape without crate-level feature toggles.
//!
//! # Determinism
//!
//! All generators take an explicit `BenchSeed` so the same seed yields
//! the same row sequence across runs. This matters for CI sticky-comment
//! diffs where two builds must produce comparable workloads.
//!
//! # Workload variants
//!
//! See `benches/postgres_write_throughput.rs` for the bench catalog
//! (batch sizes for `data_row`, per-entity single-row vs. batch
//! coverage, RLS scoping).

#![allow(
    clippy::arithmetic_side_effects,
    clippy::as_conversions,
    clippy::cast_precision_loss,
    clippy::default_numeric_fallback,
    clippy::expect_used,
    clippy::float_arithmetic,
    clippy::missing_panics_doc,
    clippy::suboptimal_flops,
    reason = "benchmark fixtures use deterministic float math, integer-to-float casts, and .expect() with stated invariants instead of silent fallbacks; indexing lints kept enabled outside the test module"
)]

use chrono::{DateTime, Duration, Utc};
use serde_json::json;
use uuid::Uuid;

use crate::types::model::{
    Annotation, AudioSpecification, BeamgramSpecification, BearingTimeRecordSpecification, DataRow,
    DataStream, DataStreamQuerySource, MetadataRow, Mission, MissionPlatform, Ontology,
    OntologyClass, Platform, PlatformAudioSpecification, PlatformBeamgramSpecification,
    PlatformBearingTimeRecordSpecification, PlatformInformation, PlatformKind,
    PlatformSpectrogramSpecification, Position, SpectrogramSpecification,
};

/// Default `anchor` for `BenchSeed`: `2023-11-14T22:13:20Z` as a Unix
/// epoch. Fixed across machines and across time so the same row index
/// yields the same datetime in every bench run.
const DEFAULT_ANCHOR_EPOCH_SECS: i64 = 1_700_000_000;

/// Fixed namespace for benchmark fixtures. Distinct from the production
/// namespace in `types::model::name_to_uuid` so benchmark data cannot
/// collide with real records.
const BENCH_NAMESPACE: Uuid = Uuid::from_bytes([
    0x42, 0x77, 0x4f, 0x14, 0x5b, 0x02, 0x4a, 0x9f, 0x9c, 0x71, 0x6a, 0xd9, 0x21, 0x8c, 0x3e, 0x5d,
]);

/// Deterministic seed for benchmark row generators.
///
/// A `BenchSeed` parameterizes every generator so the same `(seed, index)`
/// pair yields the same row. The seed is mixed into UUID v5 namespaces
/// and used as an offset for time and numeric fields.
#[derive(Debug, Clone, Copy)]
pub struct BenchSeed {
    /// Base datetime for time-series rows. All `datetime` values are
    /// offset from this anchor by a per-row delta so successive rows
    /// have strictly increasing timestamps.
    pub anchor: DateTime<Utc>,
    /// Seed prefix used to derive deterministic UUID v5 values. A
    /// nonzero value isolates one bench run from another so concurrent
    /// runs do not collide on `INSERT ON CONFLICT` paths.
    pub seed: u64,
    /// Length of every `vector` payload in `DataRow`. Realistic values
    /// for Horizon's streaming path are 256 (narrowband spectrogram bin)
    /// to 4096 (bearing-time record fan-out).
    pub vector_length: usize,
}

impl Default for BenchSeed {
    fn default() -> Self {
        Self {
            anchor: DateTime::from_timestamp(DEFAULT_ANCHOR_EPOCH_SECS, 0)
                .expect("DEFAULT_ANCHOR_EPOCH_SECS is a valid Unix epoch"),
            seed: 0,
            vector_length: 512,
        }
    }
}

/// Derive a deterministic UUID v5 from a seed and label.
///
/// The same `(seed, label)` pair yields the same UUID across runs and
/// across the Rust and Python harnesses (the Python counterpart mirrors
/// this namespace and algorithm).
#[must_use]
pub fn uuid_for(seed: u64, label: &str) -> Uuid {
    let composite = format!("bench:{seed}:{label}");
    Uuid::new_v5(&BENCH_NAMESPACE, composite.as_bytes())
}

/// Build a deterministic `Platform` row.
///
/// `name` and `free_text` use the canonical bench string format
/// `bench-{entity}-{seed}-{index:06}` shared with the Python harness.
/// The seed prefix isolates concurrent bench runs from each other;
/// the six-digit zero-padded index keeps lexicographic sort order
/// aligned with numeric order for diagnostic logs.
#[must_use]
pub fn platform(seed: BenchSeed, index: u64) -> Platform {
    let label = format!("bench-platform-{seed}-{index:06}", seed = seed.seed);
    Platform {
        created_datetime: None,
        end_datetime: None,
        free_text: Some(label.clone()),
        id: Some(uuid_for(seed.seed, &format!("platform:{index}"))),
        kind_id: None,
        modified_datetime: None,
        name: Some(label),
        organization_id: None,
        position: Some(Position(
            f64::from(u32::try_from(index & 0xFFFF).expect("masked to 16 bits, fits u32"))
                .mul_add(0.001, -180.0),
            f64::from(u32::try_from(index & 0xFFFF).expect("masked to 16 bits, fits u32"))
                .mul_add(0.0005, -90.0),
        )),
        start_datetime: Some(seed.anchor),
    }
}

/// Build a deterministic `PlatformInformation` row rooted on the given platform.
#[must_use]
pub fn platform_information(seed: BenchSeed, platform_id: Uuid, index: u64) -> PlatformInformation {
    PlatformInformation {
        created_datetime: None,
        id: Some(uuid_for(
            seed.seed,
            &format!("platform_information:{platform_id}:{index}"),
        )),
        modified_datetime: None,
        organization_id: None,
        platform_id,
        properties: json!({ "bench": true, "index": index }),
    }
}

/// Build a deterministic `PlatformKind` row.
#[must_use]
pub fn platform_kind(seed: BenchSeed, index: u64) -> PlatformKind {
    let label = format!("bench-platform-kind-{seed}-{index:06}", seed = seed.seed);
    PlatformKind {
        created_datetime: None,
        id: Some(uuid_for(seed.seed, &format!("platform_kind:{index}"))),
        image_url: None,
        long_description: None,
        modified_datetime: None,
        name: Some(label),
        organization_id: None,
        short_description: None,
    }
}

/// Build a deterministic `DataStream` rooted on the given platform.
#[must_use]
pub fn data_stream(seed: BenchSeed, platform_id: Uuid, index: u64) -> DataStream {
    DataStream {
        created_datetime: None,
        id: Some(uuid_for(
            seed.seed,
            &format!("data_stream:{platform_id}:{index}"),
        )),
        modified_datetime: None,
        name: Some(format!(
            "bench-data-stream-{seed}-{index:06}",
            seed = seed.seed
        )),
        organization_id: None,
        platform_id: Some(platform_id),
        query_source: DataStreamQuerySource::Postgres,
    }
}

/// Build a deterministic `Mission` row.
///
/// `end_datetime` is `seed.anchor + 1h` (constant across rows) so the
/// mission has a fixed one-hour duration regardless of which row index
/// generated it. The Python harness applies the same convention.
#[must_use]
pub fn mission(seed: BenchSeed, index: u64) -> Mission {
    let label = format!("bench-mission-{seed}-{index:06}", seed = seed.seed);
    Mission {
        created_datetime: None,
        end_datetime: Some(seed.anchor + Duration::hours(1)),
        free_text: Some(label.clone()),
        id: Some(uuid_for(seed.seed, &format!("mission:{index}"))),
        modified_datetime: None,
        name: Some(label),
        organization_id: None,
        position: None,
        start_datetime: Some(seed.anchor),
    }
}

/// Build a deterministic `MissionPlatform` row linking the given mission and platform.
#[must_use]
pub fn mission_platform(
    seed: BenchSeed,
    mission_id: Uuid,
    platform_id: Uuid,
    index: u64,
) -> MissionPlatform {
    MissionPlatform {
        created_datetime: None,
        id: Some(uuid_for(
            seed.seed,
            &format!("mission_platform:{mission_id}:{platform_id}:{index}"),
        )),
        mission_id: Some(mission_id),
        modified_datetime: None,
        organization_id: None,
        platform_id: Some(platform_id),
    }
}

/// Build a deterministic `Ontology` row.
#[must_use]
pub fn ontology(seed: BenchSeed, index: u64) -> Ontology {
    let label = format!("bench-ontology-{seed}-{index:06}", seed = seed.seed);
    Ontology {
        created_datetime: None,
        description: Some(label.clone()),
        id: Some(uuid_for(seed.seed, &format!("ontology:{index}"))),
        modified_datetime: None,
        name: Some(label),
        organization_id: None,
    }
}

/// Build a deterministic `OntologyClass` row anchored on a parent ontology.
#[must_use]
pub fn ontology_class(seed: BenchSeed, ontology_id: Uuid, index: u64) -> OntologyClass {
    let label = format!("bench-ontology-class-{seed}-{index:06}", seed = seed.seed);
    OntologyClass {
        created_datetime: None,
        description: Some(label.clone()),
        id: Some(uuid_for(
            seed.seed,
            &format!("ontology_class:{ontology_id}:{index}"),
        )),
        modified_datetime: None,
        name: Some(label),
        ontology_id,
        order: Some(i32::try_from(index & 0x7FFF_FFFF).expect("masked to 31 bits, fits i32")),
        organization_id: None,
        parent_id: None,
        relationship_type: Some("is_a".to_owned()),
    }
}

/// Build a deterministic `AudioSpecification` row.
#[must_use]
pub fn audio_specification(seed: BenchSeed, index: u64) -> AudioSpecification {
    AudioSpecification {
        bit_depth: 24,
        channel_count: 1,
        channel_index: 0,
        created_datetime: None,
        encoding: "pcm_float".to_owned(),
        id: Some(uuid_for(seed.seed, &format!("audio_specification:{index}"))),
        modified_datetime: None,
        organization_id: None,
        sample_rate: 48_000,
    }
}

/// Build a deterministic `BeamgramSpecification` row.
#[must_use]
pub fn beamgram_specification(seed: BenchSeed, index: u64) -> BeamgramSpecification {
    BeamgramSpecification {
        center_bearing: Some(0.0),
        center_bin_width: Some(1.0),
        created_datetime: None,
        elevation_increment: Some(1.0),
        fft_sample_count: Some(4096),
        id: Some(uuid_for(
            seed.seed,
            &format!("beamgram_specification:{index}"),
        )),
        lower_elevation: Some(-30.0),
        max_frequency: Some(24_000.0),
        min_frequency: Some(10.0),
        modified_datetime: None,
        name: Some(format!(
            "bench-beamgram-specification-{seed}-{index:06}",
            seed = seed.seed
        )),
        normalizer: Some("split_window".to_owned()),
        organization_id: None,
        update_rate_ms: Some(1_000),
        upper_elevation: Some(30.0),
    }
}

/// Build a deterministic `BearingTimeRecordSpecification` row.
#[must_use]
pub fn bearing_time_record_specification(
    seed: BenchSeed,
    index: u64,
) -> BearingTimeRecordSpecification {
    BearingTimeRecordSpecification {
        amplitude_unit_mode: Some("relative".to_owned()),
        baffle_bearing_list: None,
        bearing_bin_count: Some(720),
        created_datetime: None,
        elevation_increment: Some(1.0),
        fft_sample_count: Some(2048),
        focus_range: Some("near".to_owned()),
        frequency_spacing: Some(11.71875),
        heading_data_type: Some("magnetic".to_owned()),
        heading_vector_index: Some(1),
        id: Some(uuid_for(seed.seed, &format!("btr_specification:{index}"))),
        lower_elevation: Some(-30.0),
        max_frequency: Some(24_000.0),
        max_pixel: Some(255),
        min_frequency: Some(10.0),
        modified_datetime: None,
        name: Some(format!(
            "bench-bearing-time-record-specification-{seed}-{index:06}",
            seed = seed.seed
        )),
        normalizer: Some("split_window".to_owned()),
        organization_id: None,
        update_rate_ms: Some(1_000),
        upper_elevation: Some(30.0),
    }
}

/// Build a deterministic `SpectrogramSpecification` row.
#[must_use]
pub fn spectrogram_specification(seed: BenchSeed, index: u64) -> SpectrogramSpecification {
    SpectrogramSpecification {
        amplitude_unit_mode: Some("relative".to_owned()),
        channel: Some(0),
        channel_role: Some("omni".to_owned()),
        created_datetime: None,
        fft_sample_count: Some(2048),
        fft_sample_overlap_count: Some(512),
        frequency_spacing: Some(11.71875),
        id: Some(uuid_for(
            seed.seed,
            &format!("spectrogram_specification:{index}"),
        )),
        modified_datetime: None,
        name: Some(format!(
            "bench-spectrogram-specification-{seed}-{index:06}",
            seed = seed.seed
        )),
        organization_id: None,
    }
}

/// Build a deterministic `PlatformAudioSpecification` join row.
#[must_use]
pub fn platform_audio_specification(
    seed: BenchSeed,
    platform_id: Uuid,
    audio_specification_id: Uuid,
    index: u64,
) -> PlatformAudioSpecification {
    PlatformAudioSpecification {
        audio_specification_id,
        created_datetime: None,
        id: Some(uuid_for(
            seed.seed,
            &format!("platform_audio_specification:{platform_id}:{audio_specification_id}:{index}"),
        )),
        modified_datetime: None,
        organization_id: None,
        platform_id,
    }
}

/// Build a deterministic `PlatformBeamgramSpecification` join row.
#[must_use]
pub fn platform_beamgram_specification(
    seed: BenchSeed,
    platform_id: Uuid,
    beamgram_specification_id: Uuid,
    index: u64,
) -> PlatformBeamgramSpecification {
    PlatformBeamgramSpecification {
        beamgram_specification_id: Some(beamgram_specification_id),
        created_datetime: None,
        id: Some(uuid_for(
            seed.seed,
            &format!(
                "platform_beamgram_specification:{platform_id}:{beamgram_specification_id}:{index}"
            ),
        )),
        modified_datetime: None,
        organization_id: None,
        platform_id: Some(platform_id),
    }
}

/// Build a deterministic `PlatformBearingTimeRecordSpecification` join row.
#[must_use]
pub fn platform_bearing_time_record_specification(
    seed: BenchSeed,
    platform_id: Uuid,
    bearing_time_record_specification_id: Uuid,
    index: u64,
) -> PlatformBearingTimeRecordSpecification {
    PlatformBearingTimeRecordSpecification {
        bearing_time_record_specification_id: Some(bearing_time_record_specification_id),
        created_datetime: None,
        id: Some(uuid_for(
            seed.seed,
            &format!(
                "platform_btr_specification:{platform_id}:{bearing_time_record_specification_id}:{index}"
            ),
        )),
        modified_datetime: None,
        organization_id: None,
        platform_id: Some(platform_id),
    }
}

/// Build a deterministic `PlatformSpectrogramSpecification` join row.
#[must_use]
pub fn platform_spectrogram_specification(
    seed: BenchSeed,
    platform_id: Uuid,
    spectrogram_specification_id: Uuid,
    index: u64,
) -> PlatformSpectrogramSpecification {
    PlatformSpectrogramSpecification {
        created_datetime: None,
        id: Some(uuid_for(
            seed.seed,
            &format!(
                "platform_spectrogram_specification:{platform_id}:{spectrogram_specification_id}:{index}"
            ),
        )),
        modified_datetime: None,
        organization_id: None,
        platform_id: Some(platform_id),
        spectrogram_specification_id: Some(spectrogram_specification_id),
    }
}

/// Build a deterministic `DataRow` with a fixed-length vector payload.
///
/// `index` controls both the datetime offset (1 ms per index) and the
/// deterministic content of the `vector` field. Successive indices
/// generate strictly increasing timestamps.
///
/// `vector_end_bound` is fixed at `24_000.0`, the Nyquist frequency in
/// Hz for a 48 kHz sample rate spectrogram (matches the
/// `audio_specification` fixture above). The
/// `data_row.vector_end_bound` column stores "the end value in the data
/// type's coordinate space that this vector represents"; for `data_type
/// = "spectrogram"` rows the coordinate space is frequency, so the
/// natural reference is Nyquist. The parallel Python harness uses
/// the same value.
#[must_use]
pub fn data_row(
    seed: BenchSeed,
    data_stream_id: Uuid,
    specification_id: Uuid,
    index: u64,
) -> DataRow {
    let index_signed =
        i64::try_from(index).expect("benchmark index must fit i64 for millisecond offset");
    let datetime = seed.anchor + Duration::milliseconds(index_signed);
    let base = (index & 0xFF) as f64;
    let vector: Vec<f64> = (0_usize..seed.vector_length)
        .map(|bin| {
            #[allow(
                clippy::cast_precision_loss,
                reason = "bench fixture, not numerical code"
            )]
            {
                base + bin as f64 * 0.01
            }
        })
        .collect();
    DataRow {
        created_datetime: None,
        data_stream_id,
        data_type: "spectrogram".to_owned(),
        datetime,
        modified_datetime: None,
        specification_id,
        vector,
        vector_end_bound: 24_000.0,
        vector_start_bound: 0.0,
    }
}

/// Build `count` deterministic `DataRow` rows in a single allocation.
#[must_use]
pub fn data_row_batch(
    seed: BenchSeed,
    data_stream_id: Uuid,
    specification_id: Uuid,
    count: usize,
) -> Vec<DataRow> {
    (0_u64..u64::try_from(count).expect("benchmark count must fit u64"))
        .map(|index| data_row(seed, data_stream_id, specification_id, index))
        .collect()
}

/// Build a deterministic `MetadataRow`.
#[must_use]
pub fn metadata_row(seed: BenchSeed, data_stream_id: Uuid, index: u64) -> MetadataRow {
    let index_signed =
        i64::try_from(index).expect("benchmark index must fit i64 for millisecond offset");
    let datetime = seed.anchor + Duration::milliseconds(index_signed);
    #[allow(
        clippy::cast_precision_loss,
        reason = "bench fixture, not numerical code"
    )]
    let lat_lon = (index as f64) * 0.000_01_f64;
    MetadataRow {
        altitude: Some(10.0),
        created_datetime: None,
        data_stream_id,
        datetime,
        heading: Some(lat_lon.rem_euclid(360.0)),
        latitude: Some(37.0 + lat_lon),
        longitude: Some(-122.0 + lat_lon),
        modified_datetime: None,
        pitch: Some(0.0),
        roll: Some(0.0),
        speed: Some(1.5),
        speed_over_ground: Some(1.5),
    }
}

/// Build `count` deterministic `MetadataRow` rows in a single allocation.
#[must_use]
pub fn metadata_row_batch(seed: BenchSeed, data_stream_id: Uuid, count: usize) -> Vec<MetadataRow> {
    (0_u64..u64::try_from(count).expect("benchmark count must fit u64"))
        .map(|index| metadata_row(seed, data_stream_id, index))
        .collect()
}

/// Build a deterministic point-style `Annotation` anchored on the given platform.
#[must_use]
pub fn annotation(seed: BenchSeed, platform_id: Uuid, index: u64) -> Annotation {
    let index_signed =
        i64::try_from(index).expect("benchmark index must fit i64 for millisecond offset");
    let datetime = seed.anchor + Duration::milliseconds(index_signed);
    Annotation {
        bearing_time_record_specification_id: None,
        confidence: Some(50.0),
        created_datetime: None,
        duration_seconds: None,
        feed_context: None,
        id: Some(uuid_for(
            seed.seed,
            &format!("annotation:{platform_id}:{index}"),
        )),
        modified_datetime: None,
        notes: Some(format!(
            "bench-annotation-{seed}-{index:06}",
            seed = seed.seed
        )),
        ontology_class_id: None,
        organization_id: None,
        parent_annotation_id: None,
        platform_id,
        spectrogram_specification_id: None,
        time_coordinates: vec![datetime],
        value_coordinates: vec![0.0],
    }
}

/// Build `count` deterministic `Annotation` rows in a single allocation.
#[must_use]
pub fn annotation_batch(seed: BenchSeed, platform_id: Uuid, count: usize) -> Vec<Annotation> {
    (0_u64..u64::try_from(count).expect("benchmark count must fit u64"))
        .map(|index| annotation(seed, platform_id, index))
        .collect()
}

#[cfg(test)]
#[allow(
    clippy::indexing_slicing,
    clippy::missing_asserts_for_indexing,
    clippy::unwrap_used,
    reason = "tests assert deterministic shape via direct indexing on small fixed-size batches"
)]
mod tests {
    use std::collections::HashSet;

    use super::*;

    #[test]
    fn seed_uuids_are_deterministic_across_calls() {
        let seed = BenchSeed::default();
        let a = uuid_for(seed.seed, "platform:0");
        let b = uuid_for(seed.seed, "platform:0");
        assert_eq!(a, b);
    }

    #[test]
    fn seed_uuids_differ_across_seeds() {
        let seed_a = BenchSeed {
            seed: 1,
            ..BenchSeed::default()
        };
        let seed_b = BenchSeed {
            seed: 2,
            ..BenchSeed::default()
        };
        assert_ne!(
            uuid_for(seed_a.seed, "platform:0"),
            uuid_for(seed_b.seed, "platform:0")
        );
    }

    #[test]
    fn data_row_batch_has_strictly_increasing_datetimes() {
        let seed = BenchSeed::default();
        let stream_id = uuid_for(seed.seed, "data_stream:0");
        let spec_id = uuid_for(seed.seed, "spec:0");
        let batch = data_row_batch(seed, stream_id, spec_id, 16);
        assert_eq!(batch.len(), 16);
        for window in batch.windows(2) {
            assert!(window[0].datetime < window[1].datetime);
        }
    }

    #[test]
    fn data_row_vector_length_matches_seed() {
        let seed = BenchSeed {
            vector_length: 128,
            ..BenchSeed::default()
        };
        let stream_id = uuid_for(seed.seed, "data_stream:0");
        let spec_id = uuid_for(seed.seed, "spec:0");
        let row = data_row(seed, stream_id, spec_id, 0);
        assert_eq!(row.vector.len(), 128);
    }

    #[test]
    fn metadata_row_batch_has_strictly_increasing_datetimes() {
        let seed = BenchSeed::default();
        let stream_id = uuid_for(seed.seed, "data_stream:0");
        let batch = metadata_row_batch(seed, stream_id, 8);
        assert_eq!(batch.len(), 8);
        for window in batch.windows(2) {
            assert!(window[0].datetime < window[1].datetime);
        }
    }

    #[test]
    fn annotation_batch_has_distinct_ids_and_increasing_first_timestamp() {
        let seed = BenchSeed::default();
        let platform_id = uuid_for(seed.seed, "platform:0");
        let batch = annotation_batch(seed, platform_id, 8);
        assert_eq!(batch.len(), 8);
        let mut seen_ids = HashSet::new();
        for annotation in &batch {
            let id = annotation.id.expect("annotation carries an id");
            assert!(seen_ids.insert(id), "annotation ids must be unique");
        }
        for window in batch.windows(2) {
            let a = window[0].time_coordinates[0];
            let b = window[1].time_coordinates[0];
            assert!(a < b, "first time_coordinate must strictly increase");
        }
    }

    #[test]
    fn platform_spec_join_ids_depend_on_specification_fk() {
        let seed = BenchSeed::default();
        let platform_id = uuid_for(seed.seed, "platform:0");
        let spec_a = uuid_for(seed.seed, "audio_specification:0");
        let spec_b = uuid_for(seed.seed, "audio_specification:1");
        let row_a = platform_audio_specification(seed, platform_id, spec_a, 0);
        let row_b = platform_audio_specification(seed, platform_id, spec_b, 0);
        assert_ne!(
            row_a.id, row_b.id,
            "platform_audio_specification id must vary with audio_specification_id"
        );

        let beam_a = uuid_for(seed.seed, "beamgram_specification:0");
        let beam_b = uuid_for(seed.seed, "beamgram_specification:1");
        let beam_row_a = platform_beamgram_specification(seed, platform_id, beam_a, 0);
        let beam_row_b = platform_beamgram_specification(seed, platform_id, beam_b, 0);
        assert_ne!(beam_row_a.id, beam_row_b.id);

        let btr_a = uuid_for(seed.seed, "btr_specification:0");
        let btr_b = uuid_for(seed.seed, "btr_specification:1");
        let btr_row_a = platform_bearing_time_record_specification(seed, platform_id, btr_a, 0);
        let btr_row_b = platform_bearing_time_record_specification(seed, platform_id, btr_b, 0);
        assert_ne!(btr_row_a.id, btr_row_b.id);

        let spectrogram_a = uuid_for(seed.seed, "spectrogram_specification:0");
        let spectrogram_b = uuid_for(seed.seed, "spectrogram_specification:1");
        let spectrogram_row_a =
            platform_spectrogram_specification(seed, platform_id, spectrogram_a, 0);
        let spectrogram_row_b =
            platform_spectrogram_specification(seed, platform_id, spectrogram_b, 0);
        assert_ne!(spectrogram_row_a.id, spectrogram_row_b.id);
    }
}
