pub use application_version::ApplicationVersion;
pub use browser::{Browser, BrowserKind};
pub use conversion::{Conversion, ConversionOpts};
pub use cookie::Cookie;
pub use custom_data::{CustomData, CustomDataOpts};
pub use device::{Device, DeviceKind};
pub use geolocation::{Geolocation, GeolocationBuilder};
pub use operating_system::{OperatingSystem, OperatingSystemKind};
pub use page_view::{PageView, PageViewOpts};
pub use unique_identifier::UniqueIdentifier;
pub use user_agent::UserAgent;

use crate::{
    data::{
        assigned_variation::AssignedVariation, cbscores::CBScores, forced_variation::ForcedVariation,
        kcs_heat::KcsHeat, page_view_visit::PageViewVisit, personalization::Personalization,
        visitor_visits::VisitorVisits,
    },
    tracking::trackable::TrackableBase,
};

pub mod application_version;
pub mod assigned_variation;
pub mod browser;
pub mod cbscores;
pub mod conversion;
pub mod cookie;
pub mod custom_data;
pub mod device;
pub mod forced_variation;
pub mod geolocation;
pub mod kcs_heat;
pub mod keyed;
pub mod operating_system;
pub mod page_view;
pub mod page_view_visit;
pub mod personalization;
pub mod simulated_variation;
pub mod unique_identifier;
pub mod user_agent;
pub mod visitor_visits;

#[derive(Debug)]
pub enum KameleoonData {
    Browser(Browser),
    Conversion(Conversion),
    Cookie(Cookie),
    CustomData(CustomData),
    Device(Device),
    Geolocation(Geolocation),
    OperatingSystem(OperatingSystem),
    PageView(PageView),
    UniqueIdentifier(UniqueIdentifier),
    UserAgent(UserAgent),
    ApplicationVersion(ApplicationVersion),
}

macro_rules! impl_into_kameleoon_data {
    ($($ty:ty => $variant:ident),+ $(,)?) => {
        $(
            impl From<$ty> for KameleoonData {
                fn from(data: $ty) -> Self {
                    KameleoonData::$variant(data)
                }
            }
        )+
    };
}

impl_into_kameleoon_data!(
    Browser => Browser,
    Conversion => Conversion,
    Cookie => Cookie,
    CustomData => CustomData,
    Device => Device,
    Geolocation => Geolocation,
    OperatingSystem => OperatingSystem,
    PageView => PageView,
    UniqueIdentifier => UniqueIdentifier,
    UserAgent => UserAgent,
    ApplicationVersion => ApplicationVersion,
);

#[derive(Debug)]
pub(crate) enum BaseData {
    AssignedVariation(AssignedVariation),
    Browser(Browser),
    CBScores(CBScores),
    Conversion(Conversion),
    Cookie(Cookie),
    CustomData(CustomData),
    Device(Device),
    ForcedVariation(ForcedVariation),
    Geolocation(Geolocation),
    KcsHeat(KcsHeat),
    OperatingSystem(OperatingSystem),
    PageView(PageView),
    PageViewVisit(PageViewVisit),
    Personalization(Personalization),
    UniqueIdentifier(UniqueIdentifier),
    UserAgent(UserAgent),
    VisitorVisits(VisitorVisits),
    ApplicationVersion(ApplicationVersion),
}

impl BaseData {
    pub fn trackable_base(&self) -> Option<&TrackableBase> {
        match self {
            // trackable data
            BaseData::AssignedVariation(v) => Some(&v.trackable_base),
            BaseData::Browser(v) => Some(&v.trackable_base),
            BaseData::Conversion(v) => Some(&v.trackable_base),
            BaseData::CustomData(v) => Some(&v.trackable_base),
            BaseData::Device(v) => Some(&v.trackable_base),
            BaseData::Geolocation(v) => Some(&v.trackable_base),
            BaseData::OperatingSystem(v) => Some(&v.trackable_base),
            BaseData::PageView(v) => Some(&v.trackable_base),
            BaseData::VisitorVisits(v) => Some(&v.trackable_base),
            // not trackable data
            BaseData::ApplicationVersion(_)
            | BaseData::UserAgent(_)
            | BaseData::UniqueIdentifier(_)
            | BaseData::Personalization(_)
            | BaseData::PageViewVisit(_)
            | BaseData::KcsHeat(_)
            | BaseData::ForcedVariation(_)
            | BaseData::Cookie(_)
            | BaseData::CBScores(_) => None,
        }
    }
}

impl From<KameleoonData> for BaseData {
    fn from(data: KameleoonData) -> Self {
        match data {
            KameleoonData::Browser(b) => BaseData::Browser(b),
            KameleoonData::Conversion(c) => BaseData::Conversion(c),
            KameleoonData::Cookie(c) => BaseData::Cookie(c),
            KameleoonData::CustomData(cd) => BaseData::CustomData(cd),
            KameleoonData::Device(d) => BaseData::Device(d),
            KameleoonData::Geolocation(g) => BaseData::Geolocation(g),
            KameleoonData::OperatingSystem(os) => BaseData::OperatingSystem(os),
            KameleoonData::PageView(pv) => BaseData::PageView(pv),
            KameleoonData::UniqueIdentifier(ui) => BaseData::UniqueIdentifier(ui),
            KameleoonData::UserAgent(ua) => BaseData::UserAgent(ua),
            KameleoonData::ApplicationVersion(av) => BaseData::ApplicationVersion(av),
        }
    }
}
