// @generated by jacquard-lexicon. DO NOT EDIT.
//
// Lexicon: org.hypercerts.context.attachment
//
// 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;

#[allow(unused_imports)]
use jacquard_common::deps::codegen::unicode_segmentation::UnicodeSegmentation;
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::xrpc::XrpcResp;
use jacquard_derive::{IntoStatic, lexicon, open_union};
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::app_bsky::richtext::facet::Facet;
use crate::com_atproto::repo::strong_ref::StrongRef;
use crate::org_hypercerts::SmallBlob;
use crate::org_hypercerts::Uri;
use crate::pub_leaflet::pages::linear_document::LinearDocument;
/// An attachment providing commentary, context, evidence, or documentary material related to a hypercert record (e.g. an activity, project, claim, or evaluation).

#[lexicon]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
#[serde(rename_all = "camelCase")]
pub struct Attachment<'a> {
    ///The files, documents, or external references included in this attachment record.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(borrow)]
    pub content: Option<Vec<AttachmentContentItem<'a>>>,
    ///The type of attachment, e.g. report, audit, evidence, testimonial, methodology, etc.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(borrow)]
    pub content_type: Option<CowStr<'a>>,
    ///Client-declared timestamp when this record was originally created.
    pub created_at: Datetime,
    ///Rich-text description, represented as a Leaflet linear document.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(borrow)]
    pub description: Option<LinearDocument<'a>>,
    ///A strong reference to the location where this attachment's subject matter occurred. The record referenced must conform with the lexicon app.certified.location.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(borrow)]
    pub location: Option<StrongRef<'a>>,
    ///Short summary of this attachment, suitable for previews and list views. Rich text annotations may be provided via `shortDescriptionFacets`.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(borrow)]
    pub short_description: Option<CowStr<'a>>,
    ///Rich text annotations for `shortDescription` (mentions, URLs, hashtags, etc).
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(borrow)]
    pub short_description_facets: Option<Vec<Facet<'a>>>,
    ///References to the subject(s) the attachment is connected to—this may be an activity claim, outcome claim, measurement, evaluation, or even another attachment. This is optional as the attachment can exist before the claim is recorded.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(borrow)]
    pub subjects: Option<Vec<StrongRef<'a>>>,
    ///Display title for this attachment (e.g. 'Impact Assessment Report', 'Audit Findings')
    #[serde(borrow)]
    pub title: CowStr<'a>,
}


#[open_union]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
#[serde(tag = "$type")]
#[serde(bound(deserialize = "'de: 'a"))]
pub enum AttachmentContentItem<'a> {
    #[serde(rename = "org.hypercerts.defs#uri")]
    Uri(Box<Uri<'a>>),
    #[serde(rename = "org.hypercerts.defs#smallBlob")]
    SmallBlob(Box<SmallBlob<'a>>),
}

/// 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 AttachmentGetRecordOutput<'a> {
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(borrow)]
    pub cid: Option<Cid<'a>>,
    #[serde(borrow)]
    pub uri: AtUri<'a>,
    #[serde(borrow)]
    pub value: Attachment<'a>,
}

impl<'a> Attachment<'a> {
    pub fn uri(
        uri: impl Into<CowStr<'a>>,
    ) -> Result<RecordUri<'a, AttachmentRecord>, UriError> {
        RecordUri::try_from_uri(AtUri::new_cow(uri.into())?)
    }
}

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

#[derive(Debug, Serialize, Deserialize)]
pub struct AttachmentRecord;
impl XrpcResp for AttachmentRecord {
    const NSID: &'static str = "org.hypercerts.context.attachment";
    const ENCODING: &'static str = "application/json";
    type Output<'de> = AttachmentGetRecordOutput<'de>;
    type Err<'de> = RecordError<'de>;
}

impl From<AttachmentGetRecordOutput<'_>> for Attachment<'_> {
    fn from(output: AttachmentGetRecordOutput<'_>) -> Self {
        use jacquard_common::IntoStatic;
        output.value.into_static()
    }
}

impl Collection for Attachment<'_> {
    const NSID: &'static str = "org.hypercerts.context.attachment";
    type Record = AttachmentRecord;
}

impl Collection for AttachmentRecord {
    const NSID: &'static str = "org.hypercerts.context.attachment";
    type Record = AttachmentRecord;
}

impl<'a> LexiconSchema for Attachment<'a> {
    fn nsid() -> &'static str {
        "org.hypercerts.context.attachment"
    }
    fn def_name() -> &'static str {
        "main"
    }
    fn lexicon_doc() -> LexiconDoc<'static> {
        lexicon_doc_org_hypercerts_context_attachment()
    }
    fn validate(&self) -> Result<(), ConstraintError> {
        if let Some(ref value) = self.content {
            #[allow(unused_comparisons)]
            if value.len() > 100usize {
                return Err(ConstraintError::MaxLength {
                    path: ValidationPath::from_field("content"),
                    max: 100usize,
                    actual: value.len(),
                });
            }
        }
        if let Some(ref value) = self.content_type {
            #[allow(unused_comparisons)]
            if <str>::len(value.as_ref()) > 64usize {
                return Err(ConstraintError::MaxLength {
                    path: ValidationPath::from_field("content_type"),
                    max: 64usize,
                    actual: <str>::len(value.as_ref()),
                });
            }
        }
        if let Some(ref value) = self.short_description {
            #[allow(unused_comparisons)]
            if <str>::len(value.as_ref()) > 3000usize {
                return Err(ConstraintError::MaxLength {
                    path: ValidationPath::from_field("short_description"),
                    max: 3000usize,
                    actual: <str>::len(value.as_ref()),
                });
            }
        }
        if let Some(ref value) = self.short_description {
            {
                let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
                if count > 300usize {
                    return Err(ConstraintError::MaxGraphemes {
                        path: ValidationPath::from_field("short_description"),
                        max: 300usize,
                        actual: count,
                    });
                }
            }
        }
        if let Some(ref value) = self.subjects {
            #[allow(unused_comparisons)]
            if value.len() > 100usize {
                return Err(ConstraintError::MaxLength {
                    path: ValidationPath::from_field("subjects"),
                    max: 100usize,
                    actual: value.len(),
                });
            }
        }
        {
            let value = &self.title;
            #[allow(unused_comparisons)]
            if <str>::len(value.as_ref()) > 256usize {
                return Err(ConstraintError::MaxLength {
                    path: ValidationPath::from_field("title"),
                    max: 256usize,
                    actual: <str>::len(value.as_ref()),
                });
            }
        }
        Ok(())
    }
}

pub mod attachment_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 Title;
        type CreatedAt;
    }
    /// Empty state - all required fields are unset
    pub struct Empty(());
    impl sealed::Sealed for Empty {}
    impl State for Empty {
        type Title = Unset;
        type CreatedAt = Unset;
    }
    ///State transition - sets the `title` field to Set
    pub struct SetTitle<S: State = Empty>(PhantomData<fn() -> S>);
    impl<S: State> sealed::Sealed for SetTitle<S> {}
    impl<S: State> State for SetTitle<S> {
        type Title = Set<members::title>;
        type CreatedAt = S::CreatedAt;
    }
    ///State transition - sets the `created_at` field to Set
    pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
    impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
    impl<S: State> State for SetCreatedAt<S> {
        type Title = S::Title;
        type CreatedAt = Set<members::created_at>;
    }
    /// Marker types for field names
    #[allow(non_camel_case_types)]
    pub mod members {
        ///Marker type for the `title` field
        pub struct title(());
        ///Marker type for the `created_at` field
        pub struct created_at(());
    }
}

/// Builder for constructing an instance of this type
pub struct AttachmentBuilder<'a, S: attachment_state::State> {
    _state: PhantomData<fn() -> S>,
    _fields: (
        Option<Vec<AttachmentContentItem<'a>>>,
        Option<CowStr<'a>>,
        Option<Datetime>,
        Option<LinearDocument<'a>>,
        Option<StrongRef<'a>>,
        Option<CowStr<'a>>,
        Option<Vec<Facet<'a>>>,
        Option<Vec<StrongRef<'a>>>,
        Option<CowStr<'a>>,
    ),
    _lifetime: PhantomData<&'a ()>,
}

impl<'a> Attachment<'a> {
    /// Create a new builder for this type
    pub fn new() -> AttachmentBuilder<'a, attachment_state::Empty> {
        AttachmentBuilder::new()
    }
}

impl<'a> AttachmentBuilder<'a, attachment_state::Empty> {
    /// Create a new builder with all fields unset
    pub fn new() -> Self {
        AttachmentBuilder {
            _state: PhantomData,
            _fields: (None, None, None, None, None, None, None, None, None),
            _lifetime: PhantomData,
        }
    }
}

impl<'a, S: attachment_state::State> AttachmentBuilder<'a, S> {
    /// Set the `content` field (optional)
    pub fn content(
        mut self,
        value: impl Into<Option<Vec<AttachmentContentItem<'a>>>>,
    ) -> Self {
        self._fields.0 = value.into();
        self
    }
    /// Set the `content` field to an Option value (optional)
    pub fn maybe_content(
        mut self,
        value: Option<Vec<AttachmentContentItem<'a>>>,
    ) -> Self {
        self._fields.0 = value;
        self
    }
}

impl<'a, S: attachment_state::State> AttachmentBuilder<'a, S> {
    /// Set the `contentType` field (optional)
    pub fn content_type(mut self, value: impl Into<Option<CowStr<'a>>>) -> Self {
        self._fields.1 = value.into();
        self
    }
    /// Set the `contentType` field to an Option value (optional)
    pub fn maybe_content_type(mut self, value: Option<CowStr<'a>>) -> Self {
        self._fields.1 = value;
        self
    }
}

impl<'a, S> AttachmentBuilder<'a, S>
where
    S: attachment_state::State,
    S::CreatedAt: attachment_state::IsUnset,
{
    /// Set the `createdAt` field (required)
    pub fn created_at(
        mut self,
        value: impl Into<Datetime>,
    ) -> AttachmentBuilder<'a, attachment_state::SetCreatedAt<S>> {
        self._fields.2 = Option::Some(value.into());
        AttachmentBuilder {
            _state: PhantomData,
            _fields: self._fields,
            _lifetime: PhantomData,
        }
    }
}

impl<'a, S: attachment_state::State> AttachmentBuilder<'a, S> {
    /// Set the `description` field (optional)
    pub fn description(mut self, value: impl Into<Option<LinearDocument<'a>>>) -> Self {
        self._fields.3 = value.into();
        self
    }
    /// Set the `description` field to an Option value (optional)
    pub fn maybe_description(mut self, value: Option<LinearDocument<'a>>) -> Self {
        self._fields.3 = value;
        self
    }
}

impl<'a, S: attachment_state::State> AttachmentBuilder<'a, S> {
    /// Set the `location` field (optional)
    pub fn location(mut self, value: impl Into<Option<StrongRef<'a>>>) -> Self {
        self._fields.4 = value.into();
        self
    }
    /// Set the `location` field to an Option value (optional)
    pub fn maybe_location(mut self, value: Option<StrongRef<'a>>) -> Self {
        self._fields.4 = value;
        self
    }
}

impl<'a, S: attachment_state::State> AttachmentBuilder<'a, S> {
    /// Set the `shortDescription` field (optional)
    pub fn short_description(mut self, value: impl Into<Option<CowStr<'a>>>) -> Self {
        self._fields.5 = value.into();
        self
    }
    /// Set the `shortDescription` field to an Option value (optional)
    pub fn maybe_short_description(mut self, value: Option<CowStr<'a>>) -> Self {
        self._fields.5 = value;
        self
    }
}

impl<'a, S: attachment_state::State> AttachmentBuilder<'a, S> {
    /// Set the `shortDescriptionFacets` field (optional)
    pub fn short_description_facets(
        mut self,
        value: impl Into<Option<Vec<Facet<'a>>>>,
    ) -> Self {
        self._fields.6 = value.into();
        self
    }
    /// Set the `shortDescriptionFacets` field to an Option value (optional)
    pub fn maybe_short_description_facets(
        mut self,
        value: Option<Vec<Facet<'a>>>,
    ) -> Self {
        self._fields.6 = value;
        self
    }
}

impl<'a, S: attachment_state::State> AttachmentBuilder<'a, S> {
    /// Set the `subjects` field (optional)
    pub fn subjects(mut self, value: impl Into<Option<Vec<StrongRef<'a>>>>) -> Self {
        self._fields.7 = value.into();
        self
    }
    /// Set the `subjects` field to an Option value (optional)
    pub fn maybe_subjects(mut self, value: Option<Vec<StrongRef<'a>>>) -> Self {
        self._fields.7 = value;
        self
    }
}

impl<'a, S> AttachmentBuilder<'a, S>
where
    S: attachment_state::State,
    S::Title: attachment_state::IsUnset,
{
    /// Set the `title` field (required)
    pub fn title(
        mut self,
        value: impl Into<CowStr<'a>>,
    ) -> AttachmentBuilder<'a, attachment_state::SetTitle<S>> {
        self._fields.8 = Option::Some(value.into());
        AttachmentBuilder {
            _state: PhantomData,
            _fields: self._fields,
            _lifetime: PhantomData,
        }
    }
}

impl<'a, S> AttachmentBuilder<'a, S>
where
    S: attachment_state::State,
    S::Title: attachment_state::IsSet,
    S::CreatedAt: attachment_state::IsSet,
{
    /// Build the final struct
    pub fn build(self) -> Attachment<'a> {
        Attachment {
            content: self._fields.0,
            content_type: self._fields.1,
            created_at: self._fields.2.unwrap(),
            description: self._fields.3,
            location: self._fields.4,
            short_description: self._fields.5,
            short_description_facets: self._fields.6,
            subjects: self._fields.7,
            title: self._fields.8.unwrap(),
            extra_data: Default::default(),
        }
    }
    /// Build the final struct with custom extra_data
    pub fn build_with_data(
        self,
        extra_data: BTreeMap<
            jacquard_common::deps::smol_str::SmolStr,
            jacquard_common::types::value::Data<'a>,
        >,
    ) -> Attachment<'a> {
        Attachment {
            content: self._fields.0,
            content_type: self._fields.1,
            created_at: self._fields.2.unwrap(),
            description: self._fields.3,
            location: self._fields.4,
            short_description: self._fields.5,
            short_description_facets: self._fields.6,
            subjects: self._fields.7,
            title: self._fields.8.unwrap(),
            extra_data: Some(extra_data),
        }
    }
}

fn lexicon_doc_org_hypercerts_context_attachment() -> 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.hypercerts.context.attachment"),
        defs: {
            let mut map = BTreeMap::new();
            map.insert(
                SmolStr::new_static("main"),
                LexUserType::Record(LexRecord {
                    description: Some(
                        CowStr::new_static(
                            "An attachment providing commentary, context, evidence, or documentary material related to a hypercert record (e.g. an activity, project, claim, or evaluation).",
                        ),
                    ),
                    key: Some(CowStr::new_static("tid")),
                    record: LexRecordRecord::Object(LexObject {
                        required: Some(
                            vec![
                                SmolStr::new_static("title"),
                                SmolStr::new_static("createdAt")
                            ],
                        ),
                        properties: {
                            #[allow(unused_mut)]
                            let mut map = BTreeMap::new();
                            map.insert(
                                SmolStr::new_static("content"),
                                LexObjectProperty::Array(LexArray {
                                    description: Some(
                                        CowStr::new_static(
                                            "The files, documents, or external references included in this attachment record.",
                                        ),
                                    ),
                                    items: LexArrayItem::Union(LexRefUnion {
                                        refs: vec![
                                            CowStr::new_static("org.hypercerts.defs#uri"),
                                            CowStr::new_static("org.hypercerts.defs#smallBlob")
                                        ],
                                        ..Default::default()
                                    }),
                                    max_length: Some(100usize),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("contentType"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static(
                                            "The type of attachment, e.g. report, audit, evidence, testimonial, methodology, etc.",
                                        ),
                                    ),
                                    max_length: Some(64usize),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("createdAt"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static(
                                            "Client-declared timestamp when this record was originally created.",
                                        ),
                                    ),
                                    format: Some(LexStringFormat::Datetime),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("description"),
                                LexObjectProperty::Ref(LexRef {
                                    r#ref: CowStr::new_static(
                                        "pub.leaflet.pages.linearDocument#main",
                                    ),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("location"),
                                LexObjectProperty::Ref(LexRef {
                                    r#ref: CowStr::new_static("com.atproto.repo.strongRef"),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("shortDescription"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static(
                                            "Short summary of this attachment, suitable for previews and list views. Rich text annotations may be provided via `shortDescriptionFacets`.",
                                        ),
                                    ),
                                    max_length: Some(3000usize),
                                    max_graphemes: Some(300usize),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("shortDescriptionFacets"),
                                LexObjectProperty::Array(LexArray {
                                    description: Some(
                                        CowStr::new_static(
                                            "Rich text annotations for `shortDescription` (mentions, URLs, hashtags, etc).",
                                        ),
                                    ),
                                    items: LexArrayItem::Ref(LexRef {
                                        r#ref: CowStr::new_static("app.bsky.richtext.facet"),
                                        ..Default::default()
                                    }),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("subjects"),
                                LexObjectProperty::Array(LexArray {
                                    description: Some(
                                        CowStr::new_static(
                                            "References to the subject(s) the attachment is connected to—this may be an activity claim, outcome claim, measurement, evaluation, or even another attachment. This is optional as the attachment can exist before the claim is recorded.",
                                        ),
                                    ),
                                    items: LexArrayItem::Ref(LexRef {
                                        r#ref: CowStr::new_static("com.atproto.repo.strongRef"),
                                        ..Default::default()
                                    }),
                                    max_length: Some(100usize),
                                    ..Default::default()
                                }),
                            );
                            map.insert(
                                SmolStr::new_static("title"),
                                LexObjectProperty::String(LexString {
                                    description: Some(
                                        CowStr::new_static(
                                            "Display title for this attachment (e.g. 'Impact Assessment Report', 'Audit Findings')",
                                        ),
                                    ),
                                    max_length: Some(256usize),
                                    ..Default::default()
                                }),
                            );
                            map
                        },
                        ..Default::default()
                    }),
                    ..Default::default()
                }),
            );
            map
        },
        ..Default::default()
    }
}