//! Wire request identifiers

use std::fmt;
use std::str::FromStr;

use efdn_types::{TypeError, UuidV7};
use serde::{Deserialize, Serialize};

#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    Hash,
    PartialOrd,
    Ord,
    Serialize,
    Deserialize,
    rkyv::Archive,
    rkyv::Serialize,
    rkyv::Deserialize,
)]
pub struct CallId(UuidV7);

#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    Hash,
    PartialOrd,
    Ord,
    Serialize,
    Deserialize,
    rkyv::Archive,
    rkyv::Serialize,
    rkyv::Deserialize,
)]
pub struct RequestId(UuidV7);

#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    Hash,
    PartialOrd,
    Ord,
    Serialize,
    Deserialize,
    rkyv::Archive,
    rkyv::Serialize,
    rkyv::Deserialize,
)]
pub struct IdempotencyKey(UuidV7);

impl CallId {
    pub fn generate() -> Self {
        Self(UuidV7::generate())
    }

    pub fn new(value: UuidV7) -> Self {
        Self(value)
    }

    pub const fn as_uuid_v7(&self) -> &UuidV7 {
        &self.0
    }
}

impl RequestId {
    pub fn generate() -> Self {
        Self(UuidV7::generate())
    }

    pub fn new(value: UuidV7) -> Self {
        Self(value)
    }

    pub const fn as_uuid_v7(&self) -> &UuidV7 {
        &self.0
    }
}

impl IdempotencyKey {
    pub fn generate() -> Self {
        Self(UuidV7::generate())
    }

    pub fn new(value: UuidV7) -> Self {
        Self(value)
    }

    pub const fn as_uuid_v7(&self) -> &UuidV7 {
        &self.0
    }
}

impl fmt::Display for CallId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Display for RequestId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Display for IdempotencyKey {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl FromStr for CallId {
    type Err = TypeError;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        value.parse::<UuidV7>().map(Self)
    }
}

impl FromStr for RequestId {
    type Err = TypeError;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        value.parse::<UuidV7>().map(Self)
    }
}

impl FromStr for IdempotencyKey {
    type Err = TypeError;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        value.parse::<UuidV7>().map(Self)
    }
}
