// @generated by jacquard-lexicon. DO NOT EDIT.
//
// Lexicon: uk.skyblur.post
//
// This file was automatically generated from Lexicon schemas.
// Any manual changes will be overwritten on the next regeneration.

//! Generated bindings for the `uk.skyblur.post` Lexicon namespace/module.
pub mod decrypt_by_cid;
pub mod delete_stored;
pub mod encrypt;
pub mod get_post;
pub mod store;


#[allow(unused_imports)]
use alloc::collections::BTreeMap;

#[allow(unused_imports)]
use core::marker::PhantomData;
use jacquard_common::{CowStr, BosStr, DefaultStr, FromStaticStr};

#[allow(unused_imports)]
use jacquard_common::deps::codegen::unicode_segmentation::UnicodeSegmentation;
use jacquard_common::deps::smol_str::SmolStr;
use jacquard_common::types::blob::BlobRef;
use jacquard_common::types::collection::{Collection, RecordError};
use jacquard_common::types::string::{AtUri, Cid, Datetime};
use jacquard_common::types::uri::{RecordUri, UriError};
use jacquard_common::types::value::Data;
use jacquard_common::xrpc::XrpcResp;
use jacquard_derive::{IntoStatic, lexicon};
use jacquard_lexicon::lexicon::LexiconDoc;
use jacquard_lexicon::schema::LexiconSchema;

#[allow(unused_imports)]
use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
use serde::{Serialize, Deserialize};
/// Record containing a Skyblur post.

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
#[serde(
    rename_all = "camelCase",
    rename = "uk.skyblur.post",
    tag = "$type",
    bound(deserialize = "S: Deserialize<'de> + BosStr")
)]
pub struct Post<S: BosStr = DefaultStr> {
    ///The post additional contents.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub additional: Option<S>,
    ///Created date assigned by client
    pub created_at: Datetime,
    ///Encrypted post body. It shoud be decrypted by the client with AES-256.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub encrypt_body: Option<BlobRef<S>>,
    ///The post main contents. Blurred text must be enclosed in brackets [].
    pub text: S,
    pub uri: AtUri<S>,
    ///For 'login', the post requires login to view (Bluesky account required). For 'password', the text only contains blurred text, and additional is always empty. The unblurred text and additional are included in the encryptBody. 'followers' restricted to author's followers. 'following' restricted to users author follows. 'mutual' restricted to mutual followers.
    pub visibility: S,
    #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
    pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
}

/// Typed wrapper for GetRecord response with this collection's record type.

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
#[serde(rename_all = "camelCase")]
pub struct PostGetRecordOutput<S: BosStr = DefaultStr> {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cid: Option<Cid<S>>,
    pub uri: AtUri<S>,
    pub value: Post<S>,
}

impl<S: BosStr> Post<S> {
    pub fn uri(uri: S) -> Result<RecordUri<S, PostRecord>, UriError> {
        RecordUri::try_from_uri(AtUri::new(uri)?)
    }
}

/// Marker type for deserializing records from this collection.

#[derive(Debug, Serialize, Deserialize)]
pub struct PostRecord;
impl XrpcResp for PostRecord {
    const NSID: &'static str = "uk.skyblur.post";
    const ENCODING: &'static str = "application/json";
    type Output<S: BosStr> = PostGetRecordOutput<S>;
    type Err = RecordError;
}

impl<S: BosStr> From<PostGetRecordOutput<S>> for Post<S> {
    fn from(output: PostGetRecordOutput<S>) -> Self {
        output.value
    }
}

impl<S: BosStr> Collection for Post<S> {
    const NSID: &'static str = "uk.skyblur.post";
    type Record = PostRecord;
}

impl Collection for PostRecord {
    const NSID: &'static str = "uk.skyblur.post";
    type Record = PostRecord;
}

impl<S: BosStr> LexiconSchema for Post<S> {
    fn nsid() -> &'static str {
        "uk.skyblur.post"
    }
    fn def_name() -> &'static str {
        "main"
    }
    fn lexicon_doc() -> LexiconDoc<'static> {
        lexicon_doc_uk_skyblur_post()
    }
    fn validate(&self) -> Result<(), ConstraintError> {
        if let Some(ref value) = self.additional {
            #[allow(unused_comparisons)]
            if <str>::len(value.as_ref()) > 100000usize {
                return Err(ConstraintError::MaxLength {
                    path: ValidationPath::from_field("additional"),
                    max: 100000usize,
                    actual: <str>::len(value.as_ref()),
                });
            }
        }
        if let Some(ref value) = self.additional {
            {
                let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
                if count > 10000usize {
                    return Err(ConstraintError::MaxGraphemes {
                        path: ValidationPath::from_field("additional"),
                        max: 10000usize,
                        actual: count,
                    });
                }
            }
        }
        {
            let value = &self.text;
            #[allow(unused_comparisons)]
            if <str>::len(value.as_ref()) > 3000usize {
                return Err(ConstraintError::MaxLength {
                    path: ValidationPath::from_field("text"),
                    max: 3000usize,
                    actual: <str>::len(value.as_ref()),
                });
            }
        }
        {
            let value = &self.text;
            {
                let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
                if count > 300usize {
                    return Err(ConstraintError::MaxGraphemes {
                        path: ValidationPath::from_field("text"),
                        max: 300usize,
                        actual: count,
                    });
                }
            }
        }
        {
            let value = &self.visibility;
            #[allow(unused_comparisons)]
            if <str>::len(value.as_ref()) > 100usize {
                return Err(ConstraintError::MaxLength {
                    path: ValidationPath::from_field("visibility"),
                    max: 100usize,
                    actual: <str>::len(value.as_ref()),
                });
            }
        }
        {
            let value = &self.visibility;
            {
                let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
                if count > 10usize {
                    return Err(ConstraintError::MaxGraphemes {
                        path: ValidationPath::from_field("visibility"),
                        max: 10usize,
                        actual: count,
                    });
                }
            }
        }
        Ok(())
    }
}

pub mod post_state {

    pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
    #[allow(unused)]
    use ::core::marker::PhantomData;
    mod sealed {
        pub trait Sealed {}
    }
    /// State trait tracking which required fields have been set
    pub trait State: sealed::Sealed {
        type CreatedAt;
        type Text;
        type Uri;
        type Visibility;
    }
    /// Empty state - all required fields are unset
    pub struct Empty(());
    impl sealed::Sealed for Empty {}
    impl State for Empty {
        type CreatedAt = Unset;
        type Text = Unset;
        type Uri = Unset;
        type Visibility = Unset;
    }
    ///State transition - sets the `created_at` field to Set
    pub struct SetCreatedAt<St: State = Empty>(PhantomData<fn() -> St>);
    impl<St: State> sealed::Sealed for SetCreatedAt<St> {}
    impl<St: State> State for SetCreatedAt<St> {
        type CreatedAt = Set<members::created_at>;
        type Text = St::Text;
        type Uri = St::Uri;
        type Visibility = St::Visibility;
    }
    ///State transition - sets the `text` field to Set
    pub struct SetText<St: State = Empty>(PhantomData<fn() -> St>);
    impl<St: State> sealed::Sealed for SetText<St> {}
    impl<St: State> State for SetText<St> {
        type CreatedAt = St::CreatedAt;
        type Text = Set<members::text>;
        type Uri = St::Uri;
        type Visibility = St::Visibility;
    }
    ///State transition - sets the `uri` field to Set
    pub struct SetUri<St: State = Empty>(PhantomData<fn() -> St>);
    impl<St: State> sealed::Sealed for SetUri<St> {}
    impl<St: State> State for SetUri<St> {
        type CreatedAt = St::CreatedAt;
        type Text = St::Text;
        type Uri = Set<members::uri>;
        type Visibility = St::Visibility;
    }
    ///State transition - sets the `visibility` field to Set
    pub struct SetVisibility<St: State = Empty>(PhantomData<fn() -> St>);
    impl<St: State> sealed::Sealed for SetVisibility<St> {}
    impl<St: State> State for SetVisibility<St> {
        type CreatedAt = St::CreatedAt;
        type Text = St::Text;
        type Uri = St::Uri;
        type Visibility = Set<members::visibility>;
    }
    /// Marker types for field names
    #[allow(non_camel_case_types)]
    pub mod members {
        ///Marker type for the `created_at` field
        pub struct created_at(());
        ///Marker type for the `text` field
        pub struct text(());
        ///Marker type for the `uri` field
        pub struct uri(());
        ///Marker type for the `visibility` field
        pub struct visibility(());
    }
}

/// Builder for constructing an instance of this type.
pub struct PostBuilder<St: post_state::State, S: BosStr = DefaultStr> {
    _state: PhantomData<fn() -> St>,
    _fields: (
        Option<S>,
        Option<Datetime>,
        Option<BlobRef<S>>,
        Option<S>,
        Option<AtUri<S>>,
        Option<S>,
    ),
    _type: PhantomData<fn() -> S>,
}

impl Post<DefaultStr> {
    /// Create a new builder for this type, using the default string type (DefaultStr = SmolStr) if needed
    pub fn new() -> PostBuilder<post_state::Empty, DefaultStr> {
        PostBuilder::new()
    }
}

impl<S: BosStr> Post<S> {
    /// Create a new builder for this type
    pub fn builder() -> PostBuilder<post_state::Empty, S> {
        PostBuilder::builder()
    }
}

impl PostBuilder<post_state::Empty, DefaultStr> {
    /// Create a new builder with all fields unset, using the default string type, if needed
    pub fn new() -> Self {
        PostBuilder {
            _state: PhantomData,
            _fields: (None, None, None, None, None, None),
            _type: PhantomData,
        }
    }
}

impl<S: BosStr> PostBuilder<post_state::Empty, S> {
    /// Create a new builder with all fields unset
    pub fn builder() -> Self {
        PostBuilder {
            _state: PhantomData,
            _fields: (None, None, None, None, None, None),
            _type: PhantomData,
        }
    }
}

impl<St: post_state::State, S: BosStr> PostBuilder<St, S> {
    /// Set the `additional` field (optional)
    pub fn additional(mut self, value: impl Into<Option<S>>) -> Self {
        self._fields.0 = value.into();
        self
    }
    /// Set the `additional` field to an Option value (optional)
    pub fn maybe_additional(mut self, value: Option<S>) -> Self {
        self._fields.0 = value;
        self
    }
}

impl<St, S: BosStr> PostBuilder<St, S>
where
    St: post_state::State,
    St::CreatedAt: post_state::IsUnset,
{
    /// Set the `createdAt` field (required)
    pub fn created_at(
        mut self,
        value: impl Into<Datetime>,
    ) -> PostBuilder<post_state::SetCreatedAt<St>, S> {
        self._fields.1 = Option::Some(value.into());
        PostBuilder {
            _state: PhantomData,
            _fields: self._fields,
            _type: PhantomData,
        }
    }
}

impl<St: post_state::State, S: BosStr> PostBuilder<St, S> {
    /// Set the `encryptBody` field (optional)
    pub fn encrypt_body(mut self, value: impl Into<Option<BlobRef<S>>>) -> Self {
        self._fields.2 = value.into();
        self
    }
    /// Set the `encryptBody` field to an Option value (optional)
    pub fn maybe_encrypt_body(mut self, value: Option<BlobRef<S>>) -> Self {
        self._fields.2 = value;
        self
    }
}

impl<St, S: BosStr> PostBuilder<St, S>
where
    St: post_state::State,
    St::Text: post_state::IsUnset,
{
    /// Set the `text` field (required)
    pub fn text(
        mut self,
        value: impl Into<S>,
    ) -> PostBuilder<post_state::SetText<St>, S> {
        self._fields.3 = Option::Some(value.into());
        PostBuilder {
            _state: PhantomData,
            _fields: self._fields,
            _type: PhantomData,
        }
    }
}

impl<St, S: BosStr> PostBuilder<St, S>
where
    St: post_state::State,
    St::Uri: post_state::IsUnset,
{
    /// Set the `uri` field (required)
    pub fn uri(
        mut self,
        value: impl Into<AtUri<S>>,
    ) -> PostBuilder<post_state::SetUri<St>, S> {
        self._fields.4 = Option::Some(value.into());
        PostBuilder {
            _state: PhantomData,
            _fields: self._fields,
            _type: PhantomData,
        }
    }
}

impl<St, S: BosStr> PostBuilder<St, S>
where
    St: post_state::State,
    St::Visibility: post_state::IsUnset,
{
    /// Set the `visibility` field (required)
    pub fn visibility(
        mut self,
        value: impl Into<S>,
    ) -> PostBuilder<post_state::SetVisibility<St>, S> {
        self._fields.5 = Option::Some(value.into());
        PostBuilder {
            _state: PhantomData,
            _fields: self._fields,
            _type: PhantomData,
        }
    }
}

impl<St, S: BosStr> PostBuilder<St, S>
where
    St: post_state::State,
    St::CreatedAt: post_state::IsSet,
    St::Text: post_state::IsSet,
    St::Uri: post_state::IsSet,
    St::Visibility: post_state::IsSet,
{
    /// Build the final struct.
    pub fn build(self) -> Post<S> {
        Post {
            additional: self._fields.0,
            created_at: self._fields.1.unwrap(),
            encrypt_body: self._fields.2,
            text: self._fields.3.unwrap(),
            uri: self._fields.4.unwrap(),
            visibility: self._fields.5.unwrap(),
            extra_data: Default::default(),
        }
    }
    /// Build the final struct with custom extra_data.
    pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> Post<S> {
        Post {
            additional: self._fields.0,
            created_at: self._fields.1.unwrap(),
            encrypt_body: self._fields.2,
            text: self._fields.3.unwrap(),
            uri: self._fields.4.unwrap(),
            visibility: self._fields.5.unwrap(),
            extra_data: Some(extra_data),
        }
    }
}

fn lexicon_doc_uk_skyblur_post() -> LexiconDoc<'static> {
    #[allow(unused_imports)]
    use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
    use jacquard_lexicon::lexicon::*;
    use alloc::collections::BTreeMap;
    LexiconDoc {
        lexicon: Lexicon::Lexicon1,
        id: CowStr::new_static("uk.skyblur.post"),
        defs: {
            let mut map = BTreeMap::new();
            map.insert(
                SmolStr::new_static("main"),
                LexUserType::Record(LexRecord {
                    description: Some(
                        CowStr::new_static("Record containing a Skyblur post."),
                    ),
                    key: Some(CowStr::new_static("tid")),
                    record: LexRecordRecord::Object(LexObject {
                        required: Some(
                            vec![
                                SmolStr::new_static("text"),
                                SmolStr::new_static("createdAt"),
                                SmolStr::new_static("uri"),
                                SmolStr::new_static("visibility")
                            ],
                        ),
                        properties: {
                            #[allow(unused_mut)]
                            let mut map = BTreeMap::new();
                            map.insert(
                                SmolStr::new_static("additional"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static("The post additional contents."),
                                    ),
                                    max_length: Some(100000usize),
                                    max_graphemes: Some(10000usize),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("createdAt"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static("Created date assigned by client"),
                                    ),
                                    format: Some(LexStringFormat::Datetime),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("encryptBody"),
                                LexObjectProperty::Blob(LexBlob { ..Default::default() }),
                            );
                            map.insert(
                                SmolStr::new_static("text"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static(
                                            "The post main contents. Blurred text must be enclosed in brackets [].",
                                        ),
                                    ),
                                    max_length: Some(3000usize),
                                    max_graphemes: Some(300usize),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("uri"),
                                LexObjectProperty::String(LexString {
                                    format: Some(LexStringFormat::AtUri),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("visibility"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static(
                                            "For 'login', the post requires login to view (Bluesky account required). For 'password', the text only contains blurred text, and additional is always empty. The unblurred text and additional are included in the encryptBody. 'followers' restricted to author's followers. 'following' restricted to users author follows. 'mutual' restricted to mutual followers.",
                                        ),
                                    ),
                                    max_length: Some(100usize),
                                    max_graphemes: Some(10usize),
                                    ..Default::default()
                                }),
                            );
                            map
                        },
                        ..Default::default()
                    }),
                    ..Default::default()
                }),
            );
            map
        },
        ..Default::default()
    }
}