Documentation
#![allow(dead_code)]
#![allow(non_snake_case)]
use newtype::NewType;
use serde::{Deserialize, Serialize};
use std::time::Duration;

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ConfigRelayDetail {
    relayIdleTime: u64,
    downloadIdleTime: u64,
    relayProtectTime: u64,
    downloadProtectTime: u64,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ConfigRelay {
    pub relayGroup: ConfigRelayDetail,
    pub relayGroupManager: ConfigRelayDetail,
}

impl ConfigRelayDetail {
    pub fn relayIdleTime(&self) -> Duration {
        Duration::from_millis(self.relayIdleTime)
    }
    pub fn downloadIdleTime(&self) -> Duration {
        Duration::from_millis(self.downloadIdleTime)
    }
    pub fn relayProtectTime(&self) -> Duration {
        Duration::from_millis(self.relayProtectTime)
    }
    pub fn downloadProtectTime(&self) -> Duration {
        Duration::from_millis(self.downloadProtectTime)
    }
}

#[derive(Deserialize, Debug, Clone)]
pub struct ConfigApi {
    ip: Option<String>,
    port: Option<u32>,
}

impl ConfigApi {
    pub fn ip(&self) -> &Option<String> {
        &self.ip
    }

    pub fn port(&self) -> &Option<u32> {
        &self.port
    }
}

#[derive(Clone, Debug, serde::Deserialize, NewType, PartialEq, Eq)]
pub struct RealHandle(String);

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MediaGlobalIndex {
    access_id: String,
    relay_group_id: String,
    relay_id: Option<String>,
}
impl MediaGlobalIndex {
    pub fn new(access_id: impl Into<String>, relay_group_id: impl Into<String>, relay_id: Option<&str>) -> Self {
        Self {
            access_id: access_id.into(),
            relay_group_id: relay_group_id.into(),
            relay_id: relay_id.map(|id| id.into()),
        }
    }
    pub fn access_id(&self) -> &str {
        &self.access_id
    }
    pub fn relay_group_id(&self) -> &str {
        &self.relay_group_id
    }
    pub fn relay_id(&self) -> &Option<String> {
        &self.relay_id
    }
}

impl TryFrom<RealHandle> for MediaGlobalIndex {
    type Error = anyhow::Error;

    fn try_from(value: RealHandle) -> Result<Self, Self::Error> {
        let parts: Vec<&str> = value.0.split('-').collect();
        let access_id = parts
            .get(0)
            .ok_or_else(|| anyhow::anyhow!("Invalid RealHandle format"))?
            .to_string();
        let relay_group_id = parts
            .get(1)
            .ok_or_else(|| anyhow::anyhow!("Invalid RealHandle format"))?
            .to_string();
        let relay_id = parts.get(2).map(|s| s.to_string());
        Ok(Self {
            access_id,
            relay_group_id,
            relay_id,
        })
    }
}

#[derive(Clone, Debug, serde::Deserialize, PartialEq, Eq)]
pub struct RealResultOk {
    handle: RealHandle,
    #[serde(default)]
    isFirstAccess: bool,
    url: String,
}
impl RealResultOk {
    pub fn new(handle: impl Into<String>, isFirstAccess: bool, url: impl Into<String>) -> Self {
        Self {
            handle: handle.into().into(),
            isFirstAccess,
            url: url.into(),
        }
    }
    // gen getter
    pub fn handle(&self) -> &RealHandle {
        &self.handle
    }

    pub fn is_first_access(&self) -> bool {
        self.isFirstAccess
    }

    pub fn url(&self) -> &str {
        &self.url
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_case_real_result() {
        let json_str = r#"
        {
            "handle": "2756985974-3446087304",
            "isFirstAccess": true,
            "url": "http://127.0.0.1:5543/3446087304/aab8c5d1-7251-4371-b4ba-3923e7be894a.live.ts"
        }
        "#;
        let real_result = serde_json::from_str::<RealResultOk>(json_str).unwrap();
        assert_eq!(
            real_result.handle().to_owned(),
            RealHandle::from("2756985974-3446087304".to_string())
        );
        assert_eq!(real_result.is_first_access(), true);
        assert_eq!(
            real_result.url(),
            "http://127.0.0.1:5543/3446087304/aab8c5d1-7251-4371-b4ba-3923e7be894a.live.ts"
        );

        assert_eq!(
            real_result,
            RealResultOk::new(
                "2756985974-3446087304",
                true,
                "http://127.0.0.1:5543/3446087304/aab8c5d1-7251-4371-b4ba-3923e7be894a.live.ts"
            )
        );
    }
    #[test]
    fn test_media_global_index() {
        {
            let handle = RealHandle::from("2756985974-3446087304-1".to_string());

            let media_global_index = MediaGlobalIndex::try_from(handle).unwrap();

            assert_eq!(
                media_global_index,
                MediaGlobalIndex::new("2756985974", "3446087304", Some("1"))
            );
        }
        {
            let handle = RealHandle::from("2756985974-3446087304".to_string());

            let media_global_index = MediaGlobalIndex::try_from(handle).unwrap();

            assert_eq!(
                media_global_index,
                MediaGlobalIndex::new("2756985974", "3446087304", None)
            );
        }
    }
}