use std::{collections::HashMap, time::SystemTime};

use serde::Deserialize;
use serde_with::{serde_as, TimestampMilliSeconds};

#[derive(Debug, Deserialize)]
pub(crate) struct RemoteVisitorDataModel {
    #[serde(rename = "currentVisit")]
    pub current_visit: Option<VisitModel>,
    #[serde(rename = "previousVisits")]
    pub previous_visits: Vec<VisitModel>,
    pub kcs: Option<HashMap<u32, HashMap<u32, f64>>>,
    pub cbs: Option<HashMap<u32, HashMap<u32, f64>>>,
}

#[serde_as]
#[derive(Debug, Deserialize)]
pub(crate) struct VisitModel {
    #[serde(rename = "timeStarted")]
    #[serde_as(as = "TimestampMilliSeconds")]
    pub time_started: SystemTime,
    #[serde(rename = "timeLastEvent")]
    #[serde_as(as = "TimestampMilliSeconds")]
    pub time_last_event: SystemTime,
    #[serde(rename = "visitorCode")]
    pub visitor_code: String,
    #[serde(rename = "customDataEvents")]
    pub custom_data_events: Option<Vec<EventModel<CustomDataModel>>>,
    #[serde(rename = "pageEvents")]
    pub page_events: Option<Vec<EventModel<PageDataModel>>>,
    #[serde(rename = "experimentEvents")]
    pub experiment_events: Option<Vec<EventModel<ExperimentDataModel>>>,
    #[serde(rename = "personalizationEvents")]
    pub personalization_events: Option<Vec<EventModel<PersonalizationDataModel>>>,
    #[serde(rename = "conversionEvents")]
    pub conversion_events: Option<Vec<EventModel<ConversionDataModel>>>,
    #[serde(rename = "geolocationEvents")]
    pub geolocation_events: Option<Vec<EventModel<GeolocationDataModel>>>,
    #[serde(rename = "staticDataEvent")]
    pub static_data_event: Option<EventModel<StaticDataModel>>,
}

#[serde_as]
#[derive(Debug, Deserialize)]
pub(crate) struct EventModel<M> {
    #[serde_as(as = "TimestampMilliSeconds")]
    pub time: SystemTime,
    pub data: M,
}

#[derive(Debug, Deserialize)]
pub(crate) struct CustomDataModel {
    pub index: u32,
    #[serde(rename = "valuesCountMap")]
    pub values_count_map: HashMap<String, u32>,
}

#[derive(Debug, Deserialize)]
pub(crate) struct ExperimentDataModel {
    pub id: u32,
    #[serde(rename = "variationId")]
    pub variation_id: u32,
}

#[derive(Debug, Deserialize)]
pub(crate) struct ConversionDataModel {
    #[serde(rename = "goalId")]
    pub goal_id: u32,
    pub revenue: f32,
    pub negative: bool,
}

#[derive(Debug, Deserialize)]
pub(crate) struct GeolocationDataModel {
    pub country: String,
    pub region: Option<String>,
    pub city: Option<String>,
}

#[derive(Debug, Deserialize)]
pub(crate) struct StaticDataModel {
    #[serde(rename = "deviceType")]
    pub device_type: Option<String>,
    pub os: Option<String>,
    // #[serde(rename = "osIndex")]
    // pub os_index: Option<i32>,
    pub browser: Option<String>,
    #[serde(rename = "browserVersion")]
    pub browser_version: Option<f32>,
    #[serde(rename = "visitNumber")]
    pub visit_number: u32,
}

#[derive(Debug, Deserialize)]
pub(crate) struct PageDataModel {
    pub href: String,
    pub title: Option<String>,
}

#[derive(Debug, Deserialize)]
pub(crate) struct PersonalizationDataModel {
    pub id: u32,
    #[serde(rename = "variationId")]
    pub variation_id: u32,
}
