// @generated by jacquard-lexicon. DO NOT EDIT.
//
// Lexicon: org.okazu-diary.feed.entry
//
// This file was automatically generated from Lexicon schemas.
// Any manual changes will be overwritten on the next regeneration.

#[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::collection::{Collection, RecordError};
use jacquard_common::types::string::{AtUri, Cid};
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};
use crate::com_atproto::label::SelfLabels;
use crate::com_atproto::repo::strong_ref::StrongRef;
use crate::org_okazu_diary::material::Tag;
/// A diary entry to record a self-gratification activity.

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
#[serde(
    rename_all = "camelCase",
    rename = "org.okazu-diary.feed.entry",
    tag = "$type",
    bound(deserialize = "S: Deserialize<'de> + BosStr")
)]
pub struct Entry<S: BosStr = DefaultStr> {
    ///User-defined date and time associated with the activity, typically the datetime of the climax of the activity or simply of the record creation. The string format must satisfy all the requirements of the `datetime` format from the Lexicon language, except the requirement of whole seconds precision, but the datetime must at least specify up to the day (e.g. valid: `4545-07-21Z`, `1919-04-05T04:05+09:00`, invalid: `1919Z`). This is a subset of ISO 8601-1:2019 datetime format, but not RFC 3339 (whose time format requires whole seconds precision).
    pub datetime: S,
    ///If `true`, indicates that there may have been unrecorded activities since the last entry, so that the data in the meantime are not reliable for statistical purposes.  Defaults to `false`.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default = "_default_entry_had_hiatus")]
    pub had_hiatus: Option<bool>,
    ///Self-label values for this post. Effectively content warnings for the note and tags.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub labels: Option<SelfLabels<S>>,
    ///Remarks on the activity.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub note: Option<S>,
    ///References to `org.okazu-diary.material.external` records associated with the activity. Leave the array empty if it is known that there is no applicable material. Omit the property if the materials are uncertain. Although this property uses a `strongRef` to make a reference to an external repository reliable to some extent, it is recommended that you copy the record to your own repository if you want to reference a record from another repository.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub subjects: Option<Vec<StrongRef<S>>>,
    ///User-specified tags for the activity.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tags: Option<Vec<Tag<S>>>,
    ///Reference to another `org.okazu-diary.feed.entry` record or an `org.okazu-diary.material.collectionItem` record from this entry is derived.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub via: Option<StrongRef<S>>,
    ///Indicates the intended audience of the entry. A `public` entry (default) is fully public. An `unlisted` entry should not be listed in public profile feeds.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub visibility: Option<EntryVisibility<S>>,
    #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
    pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
}

/// Indicates the intended audience of the entry. A `public` entry (default) is fully public. An `unlisted` entry should not be listed in public profile feeds.

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum EntryVisibility<S: BosStr = DefaultStr> {
    Public,
    Unlisted,
    Other(S),
}

impl<S: BosStr> EntryVisibility<S> {
    pub fn as_str(&self) -> &str {
        match self {
            Self::Public => "public",
            Self::Unlisted => "unlisted",
            Self::Other(s) => s.as_ref(),
        }
    }
    /// Construct from a string-like value, matching known values.
    pub fn from_value(s: S) -> Self {
        match s.as_ref() {
            "public" => Self::Public,
            "unlisted" => Self::Unlisted,
            _ => Self::Other(s),
        }
    }
}

impl<S: BosStr> core::fmt::Display for EntryVisibility<S> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

impl<S: BosStr> AsRef<str> for EntryVisibility<S> {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl<S: BosStr> Serialize for EntryVisibility<S> {
    fn serialize<Ser>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error>
    where
        Ser: serde::Serializer,
    {
        serializer.serialize_str(self.as_str())
    }
}

impl<'de, S: Deserialize<'de> + BosStr> Deserialize<'de> for EntryVisibility<S> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = S::deserialize(deserializer)?;
        Ok(Self::from_value(s))
    }
}

impl<S: BosStr + Default> Default for EntryVisibility<S> {
    fn default() -> Self {
        Self::Other(Default::default())
    }
}

impl<S: BosStr> jacquard_common::IntoStatic for EntryVisibility<S>
where
    S: BosStr + jacquard_common::IntoStatic,
    S::Output: BosStr,
{
    type Output = EntryVisibility<S::Output>;
    fn into_static(self) -> Self::Output {
        match self {
            EntryVisibility::Public => EntryVisibility::Public,
            EntryVisibility::Unlisted => EntryVisibility::Unlisted,
            EntryVisibility::Other(v) => EntryVisibility::Other(v.into_static()),
        }
    }
}

/// 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 EntryGetRecordOutput<S: BosStr = DefaultStr> {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cid: Option<Cid<S>>,
    pub uri: AtUri<S>,
    pub value: Entry<S>,
}

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

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

#[derive(Debug, Serialize, Deserialize)]
pub struct EntryRecord;
impl XrpcResp for EntryRecord {
    const NSID: &'static str = "org.okazu-diary.feed.entry";
    const ENCODING: &'static str = "application/json";
    type Output<S: BosStr> = EntryGetRecordOutput<S>;
    type Err = RecordError;
}

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

impl<S: BosStr> Collection for Entry<S> {
    const NSID: &'static str = "org.okazu-diary.feed.entry";
    type Record = EntryRecord;
}

impl Collection for EntryRecord {
    const NSID: &'static str = "org.okazu-diary.feed.entry";
    type Record = EntryRecord;
}

impl<S: BosStr> LexiconSchema for Entry<S> {
    fn nsid() -> &'static str {
        "org.okazu-diary.feed.entry"
    }
    fn def_name() -> &'static str {
        "main"
    }
    fn lexicon_doc() -> LexiconDoc<'static> {
        lexicon_doc_org_okazu_diary_feed_entry()
    }
    fn validate(&self) -> Result<(), ConstraintError> {
        if let Some(ref value) = self.note {
            #[allow(unused_comparisons)]
            if <str>::len(value.as_ref()) > 5000usize {
                return Err(ConstraintError::MaxLength {
                    path: ValidationPath::from_field("note"),
                    max: 5000usize,
                    actual: <str>::len(value.as_ref()),
                });
            }
        }
        if let Some(ref value) = self.note {
            {
                let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
                if count > 500usize {
                    return Err(ConstraintError::MaxGraphemes {
                        path: ValidationPath::from_field("note"),
                        max: 500usize,
                        actual: count,
                    });
                }
            }
        }
        if let Some(ref value) = self.subjects {
            #[allow(unused_comparisons)]
            if value.len() > 16usize {
                return Err(ConstraintError::MaxLength {
                    path: ValidationPath::from_field("subjects"),
                    max: 16usize,
                    actual: value.len(),
                });
            }
        }
        if let Some(ref value) = self.tags {
            #[allow(unused_comparisons)]
            if value.len() > 64usize {
                return Err(ConstraintError::MaxLength {
                    path: ValidationPath::from_field("tags"),
                    max: 64usize,
                    actual: value.len(),
                });
            }
        }
        Ok(())
    }
}

fn _default_entry_had_hiatus() -> Option<bool> {
    Some(false)
}

pub mod entry_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 Datetime;
    }
    /// Empty state - all required fields are unset
    pub struct Empty(());
    impl sealed::Sealed for Empty {}
    impl State for Empty {
        type Datetime = Unset;
    }
    ///State transition - sets the `datetime` field to Set
    pub struct SetDatetime<St: State = Empty>(PhantomData<fn() -> St>);
    impl<St: State> sealed::Sealed for SetDatetime<St> {}
    impl<St: State> State for SetDatetime<St> {
        type Datetime = Set<members::datetime>;
    }
    /// Marker types for field names
    #[allow(non_camel_case_types)]
    pub mod members {
        ///Marker type for the `datetime` field
        pub struct datetime(());
    }
}

/// Builder for constructing an instance of this type.
pub struct EntryBuilder<St: entry_state::State, S: BosStr = DefaultStr> {
    _state: PhantomData<fn() -> St>,
    _fields: (
        Option<S>,
        Option<bool>,
        Option<SelfLabels<S>>,
        Option<S>,
        Option<Vec<StrongRef<S>>>,
        Option<Vec<Tag<S>>>,
        Option<StrongRef<S>>,
        Option<EntryVisibility<S>>,
    ),
    _type: PhantomData<fn() -> S>,
}

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

impl<S: BosStr> Entry<S> {
    /// Create a new builder for this type
    pub fn builder() -> EntryBuilder<entry_state::Empty, S> {
        EntryBuilder::builder()
    }
}

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

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

impl<St, S: BosStr> EntryBuilder<St, S>
where
    St: entry_state::State,
    St::Datetime: entry_state::IsUnset,
{
    /// Set the `datetime` field (required)
    pub fn datetime(
        mut self,
        value: impl Into<S>,
    ) -> EntryBuilder<entry_state::SetDatetime<St>, S> {
        self._fields.0 = Option::Some(value.into());
        EntryBuilder {
            _state: PhantomData,
            _fields: self._fields,
            _type: PhantomData,
        }
    }
}

impl<St: entry_state::State, S: BosStr> EntryBuilder<St, S> {
    /// Set the `hadHiatus` field (optional)
    pub fn had_hiatus(mut self, value: impl Into<Option<bool>>) -> Self {
        self._fields.1 = value.into();
        self
    }
    /// Set the `hadHiatus` field to an Option value (optional)
    pub fn maybe_had_hiatus(mut self, value: Option<bool>) -> Self {
        self._fields.1 = value;
        self
    }
}

impl<St: entry_state::State, S: BosStr> EntryBuilder<St, S> {
    /// Set the `labels` field (optional)
    pub fn labels(mut self, value: impl Into<Option<SelfLabels<S>>>) -> Self {
        self._fields.2 = value.into();
        self
    }
    /// Set the `labels` field to an Option value (optional)
    pub fn maybe_labels(mut self, value: Option<SelfLabels<S>>) -> Self {
        self._fields.2 = value;
        self
    }
}

impl<St: entry_state::State, S: BosStr> EntryBuilder<St, S> {
    /// Set the `note` field (optional)
    pub fn note(mut self, value: impl Into<Option<S>>) -> Self {
        self._fields.3 = value.into();
        self
    }
    /// Set the `note` field to an Option value (optional)
    pub fn maybe_note(mut self, value: Option<S>) -> Self {
        self._fields.3 = value;
        self
    }
}

impl<St: entry_state::State, S: BosStr> EntryBuilder<St, S> {
    /// Set the `subjects` field (optional)
    pub fn subjects(mut self, value: impl Into<Option<Vec<StrongRef<S>>>>) -> Self {
        self._fields.4 = value.into();
        self
    }
    /// Set the `subjects` field to an Option value (optional)
    pub fn maybe_subjects(mut self, value: Option<Vec<StrongRef<S>>>) -> Self {
        self._fields.4 = value;
        self
    }
}

impl<St: entry_state::State, S: BosStr> EntryBuilder<St, S> {
    /// Set the `tags` field (optional)
    pub fn tags(mut self, value: impl Into<Option<Vec<Tag<S>>>>) -> Self {
        self._fields.5 = value.into();
        self
    }
    /// Set the `tags` field to an Option value (optional)
    pub fn maybe_tags(mut self, value: Option<Vec<Tag<S>>>) -> Self {
        self._fields.5 = value;
        self
    }
}

impl<St: entry_state::State, S: BosStr> EntryBuilder<St, S> {
    /// Set the `via` field (optional)
    pub fn via(mut self, value: impl Into<Option<StrongRef<S>>>) -> Self {
        self._fields.6 = value.into();
        self
    }
    /// Set the `via` field to an Option value (optional)
    pub fn maybe_via(mut self, value: Option<StrongRef<S>>) -> Self {
        self._fields.6 = value;
        self
    }
}

impl<St: entry_state::State, S: BosStr> EntryBuilder<St, S> {
    /// Set the `visibility` field (optional)
    pub fn visibility(mut self, value: impl Into<Option<EntryVisibility<S>>>) -> Self {
        self._fields.7 = value.into();
        self
    }
    /// Set the `visibility` field to an Option value (optional)
    pub fn maybe_visibility(mut self, value: Option<EntryVisibility<S>>) -> Self {
        self._fields.7 = value;
        self
    }
}

impl<St, S: BosStr> EntryBuilder<St, S>
where
    St: entry_state::State,
    St::Datetime: entry_state::IsSet,
{
    /// Build the final struct.
    pub fn build(self) -> Entry<S> {
        Entry {
            datetime: self._fields.0.unwrap(),
            had_hiatus: self._fields.1.or_else(|| Some(false)),
            labels: self._fields.2,
            note: self._fields.3,
            subjects: self._fields.4,
            tags: self._fields.5,
            via: self._fields.6,
            visibility: self._fields.7,
            extra_data: Default::default(),
        }
    }
    /// Build the final struct with custom extra_data.
    pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> Entry<S> {
        Entry {
            datetime: self._fields.0.unwrap(),
            had_hiatus: self._fields.1.or_else(|| Some(false)),
            labels: self._fields.2,
            note: self._fields.3,
            subjects: self._fields.4,
            tags: self._fields.5,
            via: self._fields.6,
            visibility: self._fields.7,
            extra_data: Some(extra_data),
        }
    }
}

fn lexicon_doc_org_okazu_diary_feed_entry() -> 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("org.okazu-diary.feed.entry"),
        defs: {
            let mut map = BTreeMap::new();
            map.insert(
                SmolStr::new_static("main"),
                LexUserType::Record(LexRecord {
                    description: Some(
                        CowStr::new_static(
                            "A diary entry to record a self-gratification activity.",
                        ),
                    ),
                    key: Some(CowStr::new_static("tid")),
                    record: LexRecordRecord::Object(LexObject {
                        required: Some(vec![SmolStr::new_static("datetime")]),
                        properties: {
                            #[allow(unused_mut)]
                            let mut map = BTreeMap::new();
                            map.insert(
                                SmolStr::new_static("datetime"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static(
                                            "User-defined date and time associated with the activity, typically the datetime of the climax of the activity or simply of the record creation. The string format must satisfy all the requirements of the `datetime` format from the Lexicon language, except the requirement of whole seconds precision, but the datetime must at least specify up to the day (e.g. valid: `4545-07-21Z`, `1919-04-05T04:05+09:00`, invalid: `1919Z`). This is a subset of ISO 8601-1:2019 datetime format, but not RFC 3339 (whose time format requires whole seconds precision).",
                                        ),
                                    ),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("hadHiatus"),
                                LexObjectProperty::Boolean(LexBoolean {
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("labels"),
                                LexObjectProperty::Union(LexRefUnion {
                                    description: Some(
                                        CowStr::new_static(
                                            "Self-label values for this post. Effectively content warnings for the note and tags.",
                                        ),
                                    ),
                                    refs: vec![
                                        CowStr::new_static("com.atproto.label.defs#selfLabels")
                                    ],
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("note"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static("Remarks on the activity."),
                                    ),
                                    max_length: Some(5000usize),
                                    max_graphemes: Some(500usize),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("subjects"),
                                LexObjectProperty::Array(LexArray {
                                    description: Some(
                                        CowStr::new_static(
                                            "References to `org.okazu-diary.material.external` records associated with the activity. Leave the array empty if it is known that there is no applicable material. Omit the property if the materials are uncertain. Although this property uses a `strongRef` to make a reference to an external repository reliable to some extent, it is recommended that you copy the record to your own repository if you want to reference a record from another repository.",
                                        ),
                                    ),
                                    items: LexArrayItem::Ref(LexRef {
                                        r#ref: CowStr::new_static("com.atproto.repo.strongRef"),
                                        ..Default::default()
                                    }),
                                    max_length: Some(16usize),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("tags"),
                                LexObjectProperty::Array(LexArray {
                                    description: Some(
                                        CowStr::new_static("User-specified tags for the activity."),
                                    ),
                                    items: LexArrayItem::Ref(LexRef {
                                        r#ref: CowStr::new_static(
                                            "org.okazu-diary.material.defs#tag",
                                        ),
                                        ..Default::default()
                                    }),
                                    max_length: Some(64usize),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("via"),
                                LexObjectProperty::Ref(LexRef {
                                    r#ref: CowStr::new_static("com.atproto.repo.strongRef"),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("visibility"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static(
                                            "Indicates the intended audience of the entry. A `public` entry (default) is fully public. An `unlisted` entry should not be listed in public profile feeds.",
                                        ),
                                    ),
                                    ..Default::default()
                                }),
                            );
                            map
                        },
                        ..Default::default()
                    }),
                    ..Default::default()
                }),
            );
            map
        },
        ..Default::default()
    }
}