// @generated by jacquard-lexicon. DO NOT EDIT.
//
// Lexicon: org.okazu-diary.material.external
//
// 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, UriValue};
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;
use crate::org_okazu_diary::material::external;
/// A descriptor of a pornographic material.

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
#[serde(
    rename_all = "camelCase",
    rename = "org.okazu-diary.material.external",
    tag = "$type",
    bound(deserialize = "S: Deserialize<'de> + BosStr")
)]
pub struct External<S: BosStr = DefaultStr> {
    ///Description of the material, typically taken from the material's HTML metadata.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<S>,
    ///General-purpose self-label values primarily for consumption by generic AT clients who may not expect the sensitive nature of this Lexicon. Publishers of this record are strongly recommended to always include at least one of the protocol-global label values; namely, `porn`, `sexual`, `graphic-media`, and `nudity`, unless the material and tags are all known to be safe by themselves. It is the safest to unconditionally include the `sexual` value, which has the `adultOnly` semantics, but it is acceptable to use a stronger (`porn`/`graphic-media`) or more moderate (`nudity`) value instead if the user decides so.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub generic_labels: Option<SelfLabels<S>>,
    ///User-specified self-label values for the material. While the Lexicon by its nature assumes the material to be possibly sensitive by default, these label values are intended to signal that a warning should be put on the material even for the explicit Okazu-Diary.org application users who are willing to see mature contents in general.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub labels: Option<SelfLabels<S>>,
    ///Reference to a record representing the material, such as a Bluesky post.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub record: Option<StrongRef<S>>,
    ///User-specified tags for the material.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tags: Option<Vec<Tag<S>>>,
    ///Link to a thumbnail of the material, typically taken from the material's HTML metadata.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub thumb: Option<external::Thumb<S>>,
    ///Title of the material, typically taken from the material's HTML `<title>` element.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub title: Option<S>,
    ///URI of the material, typically an HTTP(S) URL. If the URL is of a Web interface for an AT resource (such as a `bsky.app` URL), the record should also include the `record` property referencing the AT resource.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub uri: Option<UriValue<S>>,
    ///Reference to an `org.okazu-diary.feed.material` record from another repository from which this collection item is derived. Clients can use this property to offer the user to update this record if the original record have updated from the referenced version.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub via: Option<StrongRef<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 ExternalGetRecordOutput<S: BosStr = DefaultStr> {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cid: Option<Cid<S>>,
    pub uri: AtUri<S>,
    pub value: External<S>,
}


#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
pub struct Thumb<S: BosStr = DefaultStr> {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cid: Option<Cid<S>>,
    pub url: UriValue<S>,
    #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
    pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
}

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

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

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

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

impl<S: BosStr> Collection for External<S> {
    const NSID: &'static str = "org.okazu-diary.material.external";
    type Record = ExternalRecord;
}

impl Collection for ExternalRecord {
    const NSID: &'static str = "org.okazu-diary.material.external";
    type Record = ExternalRecord;
}

impl<S: BosStr> LexiconSchema for External<S> {
    fn nsid() -> &'static str {
        "org.okazu-diary.material.external"
    }
    fn def_name() -> &'static str {
        "main"
    }
    fn lexicon_doc() -> LexiconDoc<'static> {
        lexicon_doc_org_okazu_diary_material_external()
    }
    fn validate(&self) -> Result<(), ConstraintError> {
        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(())
    }
}

impl<S: BosStr> LexiconSchema for Thumb<S> {
    fn nsid() -> &'static str {
        "org.okazu-diary.material.external"
    }
    fn def_name() -> &'static str {
        "thumb"
    }
    fn lexicon_doc() -> LexiconDoc<'static> {
        lexicon_doc_org_okazu_diary_material_external()
    }
    fn validate(&self) -> Result<(), ConstraintError> {
        Ok(())
    }
}

pub mod external_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 {}
    /// Empty state - all required fields are unset
    pub struct Empty(());
    impl sealed::Sealed for Empty {}
    impl State for Empty {}
    /// Marker types for field names
    #[allow(non_camel_case_types)]
    pub mod members {}
}

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

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

impl<S: BosStr> External<S> {
    /// Create a new builder for this type
    pub fn builder() -> ExternalBuilder<external_state::Empty, S> {
        ExternalBuilder::builder()
    }
}

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

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

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

impl<St: external_state::State, S: BosStr> ExternalBuilder<St, S> {
    /// Set the `genericLabels` field (optional)
    pub fn generic_labels(mut self, value: impl Into<Option<SelfLabels<S>>>) -> Self {
        self._fields.1 = value.into();
        self
    }
    /// Set the `genericLabels` field to an Option value (optional)
    pub fn maybe_generic_labels(mut self, value: Option<SelfLabels<S>>) -> Self {
        self._fields.1 = value;
        self
    }
}

impl<St: external_state::State, S: BosStr> ExternalBuilder<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: external_state::State, S: BosStr> ExternalBuilder<St, S> {
    /// Set the `record` field (optional)
    pub fn record(mut self, value: impl Into<Option<StrongRef<S>>>) -> Self {
        self._fields.3 = value.into();
        self
    }
    /// Set the `record` field to an Option value (optional)
    pub fn maybe_record(mut self, value: Option<StrongRef<S>>) -> Self {
        self._fields.3 = value;
        self
    }
}

impl<St: external_state::State, S: BosStr> ExternalBuilder<St, S> {
    /// Set the `tags` field (optional)
    pub fn tags(mut self, value: impl Into<Option<Vec<Tag<S>>>>) -> Self {
        self._fields.4 = 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.4 = value;
        self
    }
}

impl<St: external_state::State, S: BosStr> ExternalBuilder<St, S> {
    /// Set the `thumb` field (optional)
    pub fn thumb(mut self, value: impl Into<Option<external::Thumb<S>>>) -> Self {
        self._fields.5 = value.into();
        self
    }
    /// Set the `thumb` field to an Option value (optional)
    pub fn maybe_thumb(mut self, value: Option<external::Thumb<S>>) -> Self {
        self._fields.5 = value;
        self
    }
}

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

impl<St: external_state::State, S: BosStr> ExternalBuilder<St, S> {
    /// Set the `uri` field (optional)
    pub fn uri(mut self, value: impl Into<Option<UriValue<S>>>) -> Self {
        self._fields.7 = value.into();
        self
    }
    /// Set the `uri` field to an Option value (optional)
    pub fn maybe_uri(mut self, value: Option<UriValue<S>>) -> Self {
        self._fields.7 = value;
        self
    }
}

impl<St: external_state::State, S: BosStr> ExternalBuilder<St, S> {
    /// Set the `via` field (optional)
    pub fn via(mut self, value: impl Into<Option<StrongRef<S>>>) -> Self {
        self._fields.8 = 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.8 = value;
        self
    }
}

impl<St, S: BosStr> ExternalBuilder<St, S>
where
    St: external_state::State,
{
    /// Build the final struct.
    pub fn build(self) -> External<S> {
        External {
            description: self._fields.0,
            generic_labels: self._fields.1,
            labels: self._fields.2,
            record: self._fields.3,
            tags: self._fields.4,
            thumb: self._fields.5,
            title: self._fields.6,
            uri: self._fields.7,
            via: self._fields.8,
            extra_data: Default::default(),
        }
    }
    /// Build the final struct with custom extra_data.
    pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> External<S> {
        External {
            description: self._fields.0,
            generic_labels: self._fields.1,
            labels: self._fields.2,
            record: self._fields.3,
            tags: self._fields.4,
            thumb: self._fields.5,
            title: self._fields.6,
            uri: self._fields.7,
            via: self._fields.8,
            extra_data: Some(extra_data),
        }
    }
}

fn lexicon_doc_org_okazu_diary_material_external() -> 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.material.external"),
        defs: {
            let mut map = BTreeMap::new();
            map.insert(
                SmolStr::new_static("main"),
                LexUserType::Record(LexRecord {
                    description: Some(
                        CowStr::new_static("A descriptor of a pornographic material."),
                    ),
                    key: Some(CowStr::new_static("tid")),
                    record: LexRecordRecord::Object(LexObject {
                        properties: {
                            #[allow(unused_mut)]
                            let mut map = BTreeMap::new();
                            map.insert(
                                SmolStr::new_static("description"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static(
                                            "Description of the material, typically taken from the material's HTML metadata.",
                                        ),
                                    ),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("genericLabels"),
                                LexObjectProperty::Union(LexRefUnion {
                                    description: Some(
                                        CowStr::new_static(
                                            "General-purpose self-label values primarily for consumption by generic AT clients who may not expect the sensitive nature of this Lexicon. Publishers of this record are strongly recommended to always include at least one of the protocol-global label values; namely, `porn`, `sexual`, `graphic-media`, and `nudity`, unless the material and tags are all known to be safe by themselves. It is the safest to unconditionally include the `sexual` value, which has the `adultOnly` semantics, but it is acceptable to use a stronger (`porn`/`graphic-media`) or more moderate (`nudity`) value instead if the user decides so.",
                                        ),
                                    ),
                                    refs: vec![
                                        CowStr::new_static("com.atproto.label.defs#selfLabels")
                                    ],
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("labels"),
                                LexObjectProperty::Union(LexRefUnion {
                                    description: Some(
                                        CowStr::new_static(
                                            "User-specified self-label values for the material. While the Lexicon by its nature assumes the material to be possibly sensitive by default, these label values are intended to signal that a warning should be put on the material even for the explicit Okazu-Diary.org application users who are willing to see mature contents in general.",
                                        ),
                                    ),
                                    refs: vec![
                                        CowStr::new_static("com.atproto.label.defs#selfLabels")
                                    ],
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("record"),
                                LexObjectProperty::Ref(LexRef {
                                    r#ref: CowStr::new_static("com.atproto.repo.strongRef"),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("tags"),
                                LexObjectProperty::Array(LexArray {
                                    description: Some(
                                        CowStr::new_static("User-specified tags for the material."),
                                    ),
                                    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("thumb"),
                                LexObjectProperty::Ref(LexRef {
                                    r#ref: CowStr::new_static("#thumb"),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("title"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static(
                                            "Title of the material, typically taken from the material's HTML `<title>` element.",
                                        ),
                                    ),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("uri"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static(
                                            "URI of the material, typically an HTTP(S) URL. If the URL is of a Web interface for an AT resource (such as a `bsky.app` URL), the record should also include the `record` property referencing the AT resource.",
                                        ),
                                    ),
                                    format: Some(LexStringFormat::Uri),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("via"),
                                LexObjectProperty::Ref(LexRef {
                                    r#ref: CowStr::new_static("com.atproto.repo.strongRef"),
                                    ..Default::default()
                                }),
                            );
                            map
                        },
                        ..Default::default()
                    }),
                    ..Default::default()
                }),
            );
            map.insert(
                SmolStr::new_static("thumb"),
                LexUserType::Object(LexObject {
                    required: Some(vec![SmolStr::new_static("url")]),
                    properties: {
                        #[allow(unused_mut)]
                        let mut map = BTreeMap::new();
                        map.insert(
                            SmolStr::new_static("cid"),
                            LexObjectProperty::String(LexString {
                                format: Some(LexStringFormat::Cid),
                                ..Default::default()
                            }),
                        );
                        map.insert(
                            SmolStr::new_static("url"),
                            LexObjectProperty::String(LexString {
                                format: Some(LexStringFormat::Uri),
                                ..Default::default()
                            }),
                        );
                        map
                    },
                    ..Default::default()
                }),
            );
            map
        },
        ..Default::default()
    }
}

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

/// Builder for constructing an instance of this type.
pub struct ThumbBuilder<St: thumb_state::State, S: BosStr = DefaultStr> {
    _state: PhantomData<fn() -> St>,
    _fields: (Option<Cid<S>>, Option<UriValue<S>>),
    _type: PhantomData<fn() -> S>,
}

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

impl<S: BosStr> Thumb<S> {
    /// Create a new builder for this type
    pub fn builder() -> ThumbBuilder<thumb_state::Empty, S> {
        ThumbBuilder::builder()
    }
}

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

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

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

impl<St, S: BosStr> ThumbBuilder<St, S>
where
    St: thumb_state::State,
    St::Url: thumb_state::IsUnset,
{
    /// Set the `url` field (required)
    pub fn url(
        mut self,
        value: impl Into<UriValue<S>>,
    ) -> ThumbBuilder<thumb_state::SetUrl<St>, S> {
        self._fields.1 = Option::Some(value.into());
        ThumbBuilder {
            _state: PhantomData,
            _fields: self._fields,
            _type: PhantomData,
        }
    }
}

impl<St, S: BosStr> ThumbBuilder<St, S>
where
    St: thumb_state::State,
    St::Url: thumb_state::IsSet,
{
    /// Build the final struct.
    pub fn build(self) -> Thumb<S> {
        Thumb {
            cid: self._fields.0,
            url: self._fields.1.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>>) -> Thumb<S> {
        Thumb {
            cid: self._fields.0,
            url: self._fields.1.unwrap(),
            extra_data: Some(extra_data),
        }
    }
}