// @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, 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, Datetime};
use jacquard_common::types::uri::{RecordUri, UriError};
use jacquard_common::types::value::Data;
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).

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
#[serde(
    rename_all = "camelCase",
    rename = "org.hypercerts.context.attachment",
    tag = "$type",
    bound(deserialize = "S: Deserialize<'de> + BosStr")
)]
pub struct Attachment<S: BosStr = DefaultStr> {
    ///The files, documents, or external references included in this attachment record.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub content: Option<Vec<AttachmentContentItem<S>>>,
    ///The type of attachment, e.g. report, audit, evidence, testimonial, methodology, etc.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub content_type: Option<S>,
    ///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")]
    pub description: Option<LinearDocument<S>>,
    ///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")]
    pub location: Option<StrongRef<S>>,
    ///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")]
    pub short_description: Option<S>,
    ///Rich text annotations for `shortDescription` (mentions, URLs, hashtags, etc).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub short_description_facets: Option<Vec<Facet<S>>>,
    ///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")]
    pub subjects: Option<Vec<StrongRef<S>>>,
    ///Display title for this attachment (e.g. 'Impact Assessment Report', 'Audit Findings')
    pub title: S,
    #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
    pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
}


#[open_union]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
#[serde(tag = "$type", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
pub enum AttachmentContentItem<S: BosStr = DefaultStr> {
    #[serde(rename = "org.hypercerts.defs#uri")]
    Uri(Box<Uri<S>>),
    #[serde(rename = "org.hypercerts.defs#smallBlob")]
    SmallBlob(Box<SmallBlob<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 AttachmentGetRecordOutput<S: BosStr = DefaultStr> {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cid: Option<Cid<S>>,
    pub uri: AtUri<S>,
    pub value: Attachment<S>,
}

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

/// 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<S: BosStr> = AttachmentGetRecordOutput<S>;
    type Err = RecordError;
}

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

impl<S: BosStr> Collection for Attachment<S> {
    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<S: BosStr> LexiconSchema for Attachment<S> {
    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 CreatedAt;
        type Title;
    }
    /// Empty state - all required fields are unset
    pub struct Empty(());
    impl sealed::Sealed for Empty {}
    impl State for Empty {
        type CreatedAt = Unset;
        type Title = 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 Title = St::Title;
    }
    ///State transition - sets the `title` field to Set
    pub struct SetTitle<St: State = Empty>(PhantomData<fn() -> St>);
    impl<St: State> sealed::Sealed for SetTitle<St> {}
    impl<St: State> State for SetTitle<St> {
        type CreatedAt = St::CreatedAt;
        type Title = Set<members::title>;
    }
    /// 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 `title` field
        pub struct title(());
    }
}

/// Builder for constructing an instance of this type.
pub struct AttachmentBuilder<St: attachment_state::State, S: BosStr = DefaultStr> {
    _state: PhantomData<fn() -> St>,
    _fields: (
        Option<Vec<AttachmentContentItem<S>>>,
        Option<S>,
        Option<Datetime>,
        Option<LinearDocument<S>>,
        Option<StrongRef<S>>,
        Option<S>,
        Option<Vec<Facet<S>>>,
        Option<Vec<StrongRef<S>>>,
        Option<S>,
    ),
    _type: PhantomData<fn() -> S>,
}

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

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

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

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

impl<St: attachment_state::State, S: BosStr> AttachmentBuilder<St, S> {
    /// Set the `content` field (optional)
    pub fn content(
        mut self,
        value: impl Into<Option<Vec<AttachmentContentItem<S>>>>,
    ) -> 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<S>>>,
    ) -> Self {
        self._fields.0 = value;
        self
    }
}

impl<St: attachment_state::State, S: BosStr> AttachmentBuilder<St, S> {
    /// Set the `contentType` field (optional)
    pub fn content_type(mut self, value: impl Into<Option<S>>) -> 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<S>) -> Self {
        self._fields.1 = value;
        self
    }
}

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

impl<St: attachment_state::State, S: BosStr> AttachmentBuilder<St, S> {
    /// Set the `description` field (optional)
    pub fn description(mut self, value: impl Into<Option<LinearDocument<S>>>) -> 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<S>>) -> Self {
        self._fields.3 = value;
        self
    }
}

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

impl<St: attachment_state::State, S: BosStr> AttachmentBuilder<St, S> {
    /// Set the `shortDescription` field (optional)
    pub fn short_description(mut self, value: impl Into<Option<S>>) -> 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<S>) -> Self {
        self._fields.5 = value;
        self
    }
}

impl<St: attachment_state::State, S: BosStr> AttachmentBuilder<St, S> {
    /// Set the `shortDescriptionFacets` field (optional)
    pub fn short_description_facets(
        mut self,
        value: impl Into<Option<Vec<Facet<S>>>>,
    ) -> 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<S>>>,
    ) -> Self {
        self._fields.6 = value;
        self
    }
}

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

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

impl<St, S: BosStr> AttachmentBuilder<St, S>
where
    St: attachment_state::State,
    St::CreatedAt: attachment_state::IsSet,
    St::Title: attachment_state::IsSet,
{
    /// Build the final struct.
    pub fn build(self) -> Attachment<S> {
        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<SmolStr, Data<S>>,
    ) -> Attachment<S> {
        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()
    }
}