use std::sync::Arc;

use crate::{
    data::keyed::Keyed,
    network::query_builder::{QueryBuilder, QueryParam},
    tracking::trackable::{Trackable, TrackableBase, TrackingStateCell},
};

const EVENT_TYPE: &str = "targetingSegment";

#[derive(Debug)]
#[cfg_attr(test, derive(Clone, PartialEq))]
pub(crate) struct TargetedSegment {
    pub(crate) id: u32,
    pub(crate) trackable_base: TrackableBase,
}

impl TargetedSegment {
    pub fn new(id: u32) -> Self {
        Self {
            id,
            trackable_base: TrackableBase::default(),
        }
    }
}

impl Keyed<u32> for TargetedSegment {
    fn key(&self) -> &u32 {
        &self.id
    }
}

impl Trackable for TargetedSegment {
    fn encode_query(&self) -> String {
        QueryBuilder::with_params(vec![
            (QueryParam::Nonce, self.trackable_base.nonce().into()),
            (QueryParam::EventType, EVENT_TYPE.into()),
            (QueryParam::SegmentId, self.id.to_string().into()),
        ])
        .build()
    }

    fn state_cell(&self) -> &Arc<TrackingStateCell> {
        self.trackable_base.state_cell()
    }
}

#[cfg(test)]
mod tests {
    use crate::utils::test_utils::remove_nonce_parameter;

    use super::*;

    #[test]
    fn test_event_type() {
        assert_eq!("targetingSegment", EVENT_TYPE);
    }

    #[test]
    fn test_new() {
        const SEGMENT_ID: u32 = 123;
        let targeted_segment = TargetedSegment::new(SEGMENT_ID);

        assert_eq!(SEGMENT_ID, targeted_segment.id);
        assert_eq!(SEGMENT_ID, *targeted_segment.key());
    }

    #[test]
    fn test_encode_query() {
        const SEGMENT_ID: u32 = 321;
        let targeted_segment = TargetedSegment::new(SEGMENT_ID);
        let expected = format!(
            "{}={}&{}={}",
            QueryParam::EventType.as_str(),
            EVENT_TYPE,
            QueryParam::SegmentId.as_str(),
            SEGMENT_ID,
        );

        let actual = remove_nonce_parameter(&targeted_segment.encode_query());

        assert_eq!(expected, actual);
    }
}
