use std::collections::{BTreeMap, HashSet};

use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{Data, DeriveInput, Expr, ExprLit, Field, Fields, Lit, Meta, Result, Type};

use crate::shared::{
    get_field_default_value, get_ousia_attr, import_ousia, is_meta_field, is_private_field,
    parse_geo_source_fields, parse_index_kinds, parse_ousia_attr,
};

const RESERVED_FIELDS: &[&str] = &["id", "owner", "type", "created_at", "updated_at"];

/// Check if meta field has #[ousia_meta(private)] attribute
fn is_meta_private(field: &Field) -> bool {
    field.attrs.iter().any(|attr| {
        if !attr.path().is_ident("ousia_meta") {
            return false;
        }

        if let Meta::List(meta_list) = &attr.meta {
            let result = meta_list.parse_args_with(
                syn::punctuated::Punctuated::<Meta, syn::Token![,]>::parse_terminated,
            );

            if let Ok(nested) = result {
                return nested.iter().any(|meta| {
                    if let Meta::Path(path) = meta {
                        path.is_ident("private")
                    } else {
                        false
                    }
                });
            }
        }
        false
    })
}

/// Extract view names from #[ousia(view(name1), view(name2))] attributes
fn extract_field_views(field: &Field) -> Vec<String> {
    let mut views = Vec::new();

    for attr in &field.attrs {
        if !attr.path().is_ident("ousia") {
            continue;
        }

        if let Meta::List(meta_list) = &attr.meta {
            let result = meta_list.parse_args_with(
                syn::punctuated::Punctuated::<Meta, syn::Token![,]>::parse_terminated,
            );

            if let Ok(nested) = result {
                for meta in nested {
                    if let Meta::List(list) = meta {
                        if list.path.is_ident("view") {
                            // Parse view(name)
                            let tokens = list.tokens.to_string();
                            views.push(tokens);
                        }
                    }
                }
            }
        }
    }

    views
}

/// Parse #[ousia_meta(view(name="field1, field2"))] attributes
fn parse_meta_views(field: &Field) -> BTreeMap<String, Vec<String>> {
    let mut meta_views = BTreeMap::new();

    for attr in &field.attrs {
        if !attr.path().is_ident("ousia_meta") {
            continue;
        }

        if let Meta::List(meta_list) = &attr.meta {
            let result = meta_list.parse_args_with(
                syn::punctuated::Punctuated::<Meta, syn::Token![,]>::parse_terminated,
            );

            if let Ok(nested) = result {
                for meta in nested {
                    if let Meta::List(list) = meta {
                        if list.path.is_ident("view") {
                            // Parse view(name="field1, field2")
                            if let Ok(nv) = syn::parse2::<syn::MetaNameValue>(list.tokens.clone()) {
                                if let Expr::Lit(ExprLit {
                                    lit: Lit::Str(s), ..
                                }) = &nv.value
                                {
                                    let view_name = nv.path.get_ident().unwrap().to_string();
                                    let fields: Vec<String> = s
                                        .value()
                                        .split(',')
                                        .map(|f| f.trim().to_string())
                                        .filter(|f| !f.is_empty())
                                        .collect();
                                    meta_views.insert(view_name, fields);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    meta_views
}

/// Validate that a view name is a valid Rust identifier
fn is_valid_rust_identifier(name: &str) -> bool {
    const RUST_KEYWORDS: &[&str] = &[
        "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn",
        "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref",
        "return", "self", "Self", "static", "struct", "super", "trait", "true", "type", "unsafe",
        "use", "where", "while", "async", "await", "dyn", "abstract", "become", "box", "do",
        "final", "macro", "override", "priv", "typeof", "unsized", "virtual", "yield", "try",
    ];

    if name.is_empty() || RUST_KEYWORDS.contains(&name) {
        return false;
    }

    let mut chars = name.chars();
    let first = chars.next().unwrap();

    if !first.is_alphabetic() && first != '_' {
        return false;
    }

    chars.all(|c| c.is_alphanumeric() || c == '_')
}

/// Default meta fields when no explicit view(default="...") is specified and not private
const DEFAULT_META_FIELDS: &[&str] = &["id", "created_at", "updated_at"];

/// Generate view struct and conversion method
fn generate_view_code(
    struct_name: &syn::Ident,
    view_name: &str,
    meta_fields: &[String],
    data_fields: &[(syn::Ident, Type)],
) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
    // Validate that view has at least one field
    if meta_fields.is_empty() && data_fields.is_empty() {
        panic!(
            "View '{}' must have at least one field. Views cannot be empty.",
            view_name
        );
    }

    // Create PascalCase view name
    let view_pascal = view_name
        .split('_')
        .map(|word| {
            let mut chars = word.chars();
            match chars.next() {
                None => String::new(),
                Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
            }
        })
        .collect::<String>();

    let view_struct_name = format_ident!("{}{}View", struct_name, view_pascal);
    let method_name = format_ident!("_{}", view_name);

    // Generate struct fields
    let mut struct_fields = Vec::new();
    let mut field_assignments = Vec::new();

    // Add meta fields
    for meta_field in meta_fields {
        match meta_field.as_str() {
            "id" => {
                struct_fields.push(quote! { pub id: uuid::Uuid });
                field_assignments.push(quote! { id: self._meta.id });
            }
            "owner" => {
                struct_fields.push(quote! { pub owner: uuid::Uuid });
                field_assignments.push(quote! { owner: self._meta.owner });
            }
            "created_at" => {
                struct_fields.push(quote! { pub created_at: chrono::DateTime<chrono::Utc> });
                field_assignments.push(quote! { created_at: self._meta.created_at });
            }
            "updated_at" => {
                struct_fields.push(quote! { pub updated_at: chrono::DateTime<chrono::Utc> });
                field_assignments.push(quote! { updated_at: self._meta.updated_at });
            }
            _ => panic!(
                "Invalid meta field: {}. Valid fields are: id, owner, created_at, updated_at",
                meta_field
            ),
        }
    }

    // Add data fields
    for (field_name, field_type) in data_fields {
        struct_fields.push(quote! { pub #field_name: #field_type });
        field_assignments.push(quote! { #field_name: self.#field_name.clone() });
    }

    let view_struct = quote! {
        #[derive(serde::Serialize, Clone, Debug)]
        pub struct #view_struct_name {
            #(#struct_fields),*
        }
    };

    let view_method = quote! {
        pub fn #method_name(&self) -> #view_struct_name {
            #view_struct_name {
                #(#field_assignments),*
            }
        }
    };

    (view_struct, view_method)
}

/// Generate the internal serialization implementation.
///
/// Emits a MessagePack-encoded `Vec<u8>` representing the object's
/// non-meta fields (including private ones). We build a one-shot
/// `Serialize` adapter that writes a named map so deserialization via
/// the user's derived `Deserialize` impl reads it back field-by-field.
fn generate_internal_serialize(
    ousia: &proc_macro2::TokenStream,
    ident: &syn::Ident,
    non_meta_fields: &[&Field],
) -> proc_macro2::TokenStream {
    let field_count = non_meta_fields.len();
    let serialize_calls = non_meta_fields.iter().map(|f| {
        let field_name = f.ident.as_ref().unwrap();
        let field_name_str = field_name.to_string();
        quote! { map.serialize_entry(#field_name_str, &self.0.#field_name)?; }
    });

    quote! {
        {
            struct __InternalView<'a>(&'a #ident);
            impl<'a> serde::Serialize for __InternalView<'a> {
                fn serialize<__S>(&self, serializer: __S) -> ::std::result::Result<__S::Ok, __S::Error>
                where
                    __S: serde::Serializer,
                {
                    use serde::ser::SerializeMap;
                    let mut map = serializer.serialize_map(Some(#field_count))?;
                    #(#serialize_calls)*
                    map.end()
                }
            }
            #ousia::__rmp_serde::to_vec_named(&__InternalView(self))
                .expect("ousia: msgpack serialization of object data failed")
        }
    }
}

pub fn generate_object_impl(input: &DeriveInput) -> Result<TokenStream> {
    let ousia = import_ousia();
    let ident = &input.ident;

    // --- get ousia attribute ---
    let attr = get_ousia_attr(&input.attrs);
    let (type_name, indexes) = parse_ousia_attr(attr);
    let type_name = type_name.unwrap_or_else(|| ident.to_string());

    // --- extract fields and identify meta field ---
    let fields = match &input.data {
        Data::Struct(s) => match &s.fields {
            Fields::Named(f) => &f.named,
            _ => panic!("OusiaObject only supports named structs"),
        },
        _ => panic!("OusiaObject only supports structs"),
    };

    // Find meta field
    let meta_fields: Vec<_> = fields.iter().filter(|f| is_meta_field(f)).collect();

    let meta_field_ident = if meta_fields.is_empty() {
        // Default to _meta if no field is marked
        fields
        .iter()
        .find(|f| f.ident.as_ref().unwrap() == "_meta")
        .map(|f| f.ident.as_ref().unwrap())
        .unwrap_or_else(|| {
            panic!(
                "No meta field found. Either mark a field with #[ousia(meta)] or use '_meta' as field name"
            )
        })
    } else if meta_fields.len() > 1 {
        panic!("Only one field can be marked with #[ousia(meta)]");
    } else {
        meta_fields[0].ident.as_ref().unwrap()
    };

    // Get all non-meta fields
    let non_meta_fields: Vec<_> = fields
        .iter()
        .filter(|f| f.ident.as_ref().unwrap() != meta_field_ident)
        .collect();

    // Validate no reserved meta field names
    for field in &non_meta_fields {
        let f_str = field.ident.as_ref().unwrap().to_string();
        if RESERVED_FIELDS.contains(&f_str.as_str()) {
            panic!(
                "Field `{}` is reserved for meta and cannot be declared in struct {}",
                f_str, ident
            );
        }
    }

    // --- Collect view information ---
    let mut all_view_names = HashSet::new();
    let mut field_view_map: BTreeMap<String, Vec<String>> = BTreeMap::new();

    // Get meta field views
    let meta_field = fields
        .iter()
        .find(|f| f.ident.as_ref().unwrap() == meta_field_ident)
        .unwrap();
    let meta_views = parse_meta_views(meta_field);
    let meta_is_private = is_meta_private(meta_field);

    // Collect all view names from meta
    for view_name in meta_views.keys() {
        if view_name != "default" {
            all_view_names.insert(view_name.clone());
        }
    }

    // Collect view names from fields
    for field in &non_meta_fields {
        let field_name = field.ident.as_ref().unwrap().to_string();
        let views = extract_field_views(field);

        for view in views {
            if !is_valid_rust_identifier(&view) {
                panic!(
                    "Invalid view name '{}' on field '{}'. View names must be valid Rust identifiers.",
                    view, field_name
                );
            }
            if view != "default" {
                all_view_names.insert(view.clone());
            }
            field_view_map
                .entry(field_name.clone())
                .or_insert_with(Vec::new)
                .push(view);
        }
    }

    // --- Generate view structs and methods ---
    let mut view_structs = Vec::new();
    let mut view_methods = Vec::new();

    for view_name in &all_view_names {
        // Get meta fields for this view
        let meta_fields = meta_views.get(view_name).cloned().unwrap_or_else(Vec::new);

        // Get data fields for this view
        let data_fields: Vec<_> = non_meta_fields
            .iter()
            .filter(|f| {
                let fname = f.ident.as_ref().unwrap().to_string();
                field_view_map
                    .get(&fname)
                    .map(|views| views.contains(view_name))
                    .unwrap_or(false)
                    && !is_private_field(f)
            })
            .map(|f| (f.ident.as_ref().unwrap().clone(), f.ty.clone()))
            .collect();

        let (view_struct, view_method) =
            generate_view_code(ident, view_name, &meta_fields, &data_fields);
        view_structs.push(view_struct);
        view_methods.push(view_method);
    }

    // --- classify indexes into scalar vs geo ---
    // Geo indexes use a virtual field name that does NOT need to exist on the
    // struct; instead, the kind carries the lat/lon source fields that must
    // exist. Geo values are stored in the `object_geo` side table, not
    // `index_meta`, so they're excluded from `index_meta_insertions`.
    // (virtual_name, lat_field, lon_field, lat_is_option, lon_is_option)
    let mut geo_indexes: Vec<(String, String, String, bool, bool)> = Vec::new();
    for (name, kind) in &indexes {
        if let Some((lat, lon)) = parse_geo_source_fields(kind) {
            let lat_field = non_meta_fields
                .iter()
                .find(|f| f.ident.as_ref().unwrap() == &lat)
                .unwrap_or_else(|| {
                    panic!(
                        "Geo index `{}`: lat field `{}` does not exist on {}",
                        name, lat, ident
                    )
                });
            let lon_field = non_meta_fields
                .iter()
                .find(|f| f.ident.as_ref().unwrap() == &lon)
                .unwrap_or_else(|| {
                    panic!(
                        "Geo index `{}`: lon field `{}` does not exist on {}",
                        name, lon, ident
                    )
                });
            let is_option = |ty: &syn::Type| -> bool {
                if let syn::Type::Path(tp) = ty {
                    if let Some(seg) = tp.path.segments.last() {
                        return seg.ident == "Option";
                    }
                }
                false
            };
            let lat_is_option = is_option(&lat_field.ty);
            let lon_is_option = is_option(&lon_field.ty);
            geo_indexes.push((name.clone(), lat, lon, lat_is_option, lon_is_option));
        }
    }

    // --- generate IndexField list for `IndexQuery::indexed_fields()` ---
    let index_fields: Vec<proc_macro2::TokenStream> = indexes
        .iter()
        .map(|(name, kind)| {
            if RESERVED_FIELDS.contains(&name.as_str()) {
                panic!(
                    "Index field `{}` is reserved for meta and cannot be indexed",
                    name
                );
            }
            let is_geo = parse_geo_source_fields(kind).is_some();
            if !is_geo
                && !non_meta_fields
                    .iter()
                    .any(|f| &f.ident.as_ref().unwrap().to_string() == name)
            {
                panic!("Indexed field `{}` does not exist on {}", name, ident);
            }

            let kinds = parse_index_kinds(kind);

            quote! {
                #ousia::query::IndexField {
                    name: #name,
                    kinds: &[#(#kinds),*],
                }
            }
        })
        .collect();

    // --- generate index_meta insertions (scalar fields only) ---
    let index_meta_insertions = indexes.iter().filter_map(|(name, kind)| {
        if parse_geo_source_fields(kind).is_some() {
            return None;
        }
        let field_name = format_ident!("{}", name);
        let name_str = name.as_str();

        Some(quote! {
            values.insert(
                #name_str.to_string(),
                #ousia::query::ToIndexValue::to_index_value(&self.#field_name)
            );
        })
    });

    // --- generate geo_points() body ---
    let has_geo_fields = !geo_indexes.is_empty();
    let geo_point_pushes = geo_indexes.iter().map(|(virtual_name, lat, lon, lat_is_option, lon_is_option)| {
        let lat_ident = format_ident!("{}", lat);
        let lon_ident = format_ident!("{}", lon);
        let virtual_name_str = virtual_name.as_str();
        if *lat_is_option || *lon_is_option {
            // Optional coordinates: only push a GeoPoint when both are Some.
            // Stores/objects without coordinates are simply absent from geo queries.
            quote! {
                {
                    if let (Some(lat_raw), Some(lon_raw)) = (self.#lat_ident, self.#lon_ident) {
                        let lat_v: f64 = lat_raw as f64;
                        let lon_v: f64 = lon_raw as f64;
                        points.push(#ousia::query::GeoPoint {
                            field: #virtual_name_str,
                            lon: lon_v,
                            lat: lat_v,
                            hash: #ousia::object::derive_geo_hash(#virtual_name_str, lon_v, lat_v),
                        });
                    }
                }
            }
        } else {
            quote! {
                {
                    let lon_v: f64 = self.#lon_ident as f64;
                    let lat_v: f64 = self.#lat_ident as f64;
                    points.push(#ousia::query::GeoPoint {
                        field: #virtual_name_str,
                        lon: lon_v,
                        lat: lat_v,
                        hash: #ousia::object::derive_geo_hash(#virtual_name_str, lon_v, lat_v),
                    });
                }
            }
        }
    });
    let geo_points_body = quote! {
        let mut points: Vec<#ousia::query::GeoPoint> = Vec::new();
        #(#geo_point_pushes)*
        points
    };

    // --- generate Indexes struct ---
    let indexes_struct_name = format_ident!("{}Fields", ident);

    // Build a map of field names to their kinds (merge multiple declarations)
    let mut field_kinds_map: BTreeMap<String, Vec<String>> = BTreeMap::new();
    for (name, kind) in &indexes {
        field_kinds_map
            .entry(name.clone())
            .or_insert_with(Vec::new)
            .push(kind.clone());
    }

    let indexes_struct_fields = field_kinds_map.keys().map(|name| {
        let field_ident = format_ident!("{}", name);
        quote! {
            pub #field_ident: #ousia::query::IndexField
        }
    });

    let indexes_const_fields = field_kinds_map.iter().map(|(name, kinds)| {
        let field_ident = format_ident!("{}", name);
        let name_str = name.as_str();

        // Collect all unique kinds for this field
        let mut all_kinds = Vec::new();
        for kind_str in kinds {
            all_kinds.extend(parse_index_kinds(kind_str));
        }

        // Remove duplicates by converting to a set-like structure
        let unique_kinds = {
            let mut seen = std::collections::HashSet::new();
            all_kinds
                .into_iter()
                .filter(move |k| {
                    let key = k.to_string();
                    seen.insert(key)
                })
                .collect::<Vec<_>>()
        };

        quote! {
            #field_ident: #ousia::query::IndexField {
                name: #name_str,
                kinds: &[#(#unique_kinds),*],
            }
        }
    });

    // --- generate Serialize implementation (default view) ---
    // Get default meta fields - empty if meta is private, otherwise use explicit or DEFAULT_META_FIELDS
    let default_meta_fields = if meta_is_private {
        Vec::new()
    } else {
        meta_views
            .get("default")
            .cloned()
            .unwrap_or_else(|| DEFAULT_META_FIELDS.iter().map(|s| s.to_string()).collect())
    };

    let serialize_meta_fields = default_meta_fields.iter().map(|field_name| {
        let meta_field = format_ident!("{}", field_name);
        quote! {
            state.serialize_field(#field_name, &self._meta.#meta_field)?;
        }
    });

    let serialize_fields = non_meta_fields.iter().filter_map(|f| {
        let field_name = f.ident.as_ref().unwrap();
        let field_name_str = field_name.to_string();

        // Skip private fields in default view
        if is_private_field(f) {
            return None;
        }

        Some(quote! {
            state.serialize_field(#field_name_str, &self.#field_name)?;
        })
    });

    let non_private_count = non_meta_fields
        .iter()
        .filter(|f| !is_private_field(f))
        .count();
    let field_count = non_private_count + default_meta_fields.len();

    // --- generate internal serialization ---
    let internal_serialize_body = generate_internal_serialize(&ousia, ident, &non_meta_fields);

    // --- generate Deserialize implementation ---
    let deserialize_field_names: Vec<_> = non_meta_fields
        .iter()
        .map(|f| f.ident.as_ref().unwrap().to_string())
        .collect();

    let deserialize_field_idents: Vec<_> = non_meta_fields
        .iter()
        .map(|f| f.ident.as_ref().unwrap())
        .collect();

    // Create UpperCamelCase enum variants from snake_case field names
    // e.g., "username" -> Username, "display_name" -> DisplayName
    let deserialize_field_variants: Vec<_> = deserialize_field_names
        .iter()
        .map(|name| {
            let camel = name
                .split('_')
                .map(|word| {
                    let mut chars = word.chars();
                    match chars.next() {
                        None => String::new(),
                        Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
                    }
                })
                .collect::<String>();
            format_ident!("{}", camel)
        })
        .collect();

    let deserialize_field_types: Vec<_> = non_meta_fields.iter().map(|f| &f.ty).collect();

    let visitor_name = format_ident!("{}Visitor", ident);

    // Handle the case where there are no data fields (only meta)
    let deserialize_impl = if non_meta_fields.is_empty() {
        // Simple case: no data fields, just create with default meta
        quote! {
            impl<'de> serde::Deserialize<'de> for #ident {
                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                where
                    D: serde::Deserializer<'de>,
                {
                    // For empty structs, we just need to consume the empty map
                    struct #visitor_name;

                    impl<'de> serde::de::Visitor<'de> for #visitor_name {
                        type Value = #ident;

                        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                            formatter.write_str(concat!("struct ", stringify!(#ident)))
                        }

                        fn visit_map<V>(self, mut map: V) -> Result<#ident, V::Error>
                        where
                            V: serde::de::MapAccess<'de>,
                        {
                            // Consume any fields in the map (ignore them)
                            while map.next_entry::<String, serde_json::Value>()?.is_some() {}

                            Ok(#ident {
                                #meta_field_ident: #ousia::object::meta::Meta::default(),
                            })
                        }

                        fn visit_unit<E>(self) -> Result<#ident, E>
                        where
                            E: serde::de::Error,
                        {
                            Ok(#ident {
                                #meta_field_ident: #ousia::object::meta::Meta::default(),
                            })
                        }
                    }

                    deserializer.deserialize_struct(stringify!(#ident), &[], #visitor_name)
                }
            }
        }
    } else {
        // Normal case: struct has data fields
        fn is_option_type(ty: &Type) -> bool {
            if let Type::Path(type_path) = ty {
                if let Some(segment) = type_path.path.segments.last() {
                    return segment.ident == "Option";
                }
            }
            false
        }

        fn should_use_default(ty: &Type) -> bool {
            // Check if type is Option (always uses default)
            if is_option_type(ty) {
                return true;
            }

            // Check for common types that implement Default
            if let Type::Path(type_path) = ty {
                if let Some(segment) = type_path.path.segments.last() {
                    let type_name = segment.ident.to_string();

                    // Common stdlib types that implement Default
                    match type_name.as_str() {
                                // Collections
                                "Vec" | "HashMap" | "HashSet" | "BTreeMap" | "BTreeSet" |
                                "VecDeque" | "LinkedList" | "BinaryHeap" |
                                // Strings
                                "String" |
                                // Numbers (all primitive number types implement Default)
                                "i8" | "i16" | "i32" | "i64" | "i128" | "isize" |
                                "u8" | "u16" | "u32" | "u64" | "u128" | "usize" |
                                "f32" | "f64" |
                                // Other common types
                                "bool" | "PathBuf" | "Duration" => return true,
                                _ => {}
                            }
                }
            }

            // For other types (including custom enums), assume they implement Default
            // The compiler will verify at compile time
            true
        }

        // Check which fields are Option types (special handling)
        let field_is_optional: Vec<bool> = non_meta_fields
            .iter()
            .map(|f| is_option_type(&f.ty))
            .collect();

        // Check which fields should use Default::default()
        let field_uses_default: Vec<bool> = non_meta_fields
            .iter()
            .map(|f| should_use_default(&f.ty))
            .collect();

        // Extract explicit default values from #[ousia(default = <expr>)]
        let field_default_values: Vec<Option<proc_macro2::TokenStream>> = non_meta_fields
            .iter()
            .map(|f| get_field_default_value(f))
            .collect();

        // Variable declarations: fields with an explicit default use Option<Option<T>> so
        // that a JSON `null` value (Some(None)) is distinguished from "not seen" (None) and
        // treated the same as missing — letting the default kick in either way.
        let var_decls: Vec<proc_macro2::TokenStream> = deserialize_field_idents
            .iter()
            .zip(deserialize_field_types.iter())
            .zip(field_default_values.iter())
            .map(|((ident, ty), default_value)| {
                if default_value.is_some() {
                    quote! { let mut #ident: Option<Option<#ty>> = None; }
                } else {
                    quote! { let mut #ident: Option<#ty> = None; }
                }
            })
            .collect();

        // Generate match arms - handle Option<T> and explicit-default fields differently
        let match_arms = deserialize_field_variants
            .iter()
            .zip(deserialize_field_idents.iter())
            .zip(deserialize_field_names.iter())
            .zip(deserialize_field_types.iter())
            .zip(field_is_optional.iter())
            .zip(field_default_values.iter())
            .map(|(((((variant, ident), name), field_type), is_opt), default_value)| {
                if *is_opt {
                    quote! {
                        Field::#variant => {
                            if #ident.is_some() {
                                return Err(serde::de::Error::duplicate_field(#name));
                            }
                            #ident = Some(map.next_value()?);
                        }
                    }
                } else if default_value.is_some() {
                    // Deserialize as Option<T> so a JSON `null` becomes None rather than
                    // a type error; the field init will apply the explicit default.
                    quote! {
                        Field::#variant => {
                            if #ident.is_some() {
                                return Err(serde::de::Error::duplicate_field(#name));
                            }
                            #ident = Some(map.next_value::<Option<#field_type>>()?);
                        }
                    }
                } else {
                    quote! {
                        Field::#variant => {
                            if #ident.is_some() {
                                return Err(serde::de::Error::duplicate_field(#name));
                            }
                            #ident = Some(map.next_value()?);
                        }
                    }
                }
            });

        // Generate field initialization - handles four cases:
        // 1. Option<T> fields
        // 2. Fields with explicit #[ousia(default = "value")] — variable is Option<Option<T>>
        // 3. Fields that implement Default
        // 4. Required fields
        let field_inits = deserialize_field_idents
            .iter()
            .zip(deserialize_field_names.iter())
            .zip(field_is_optional.iter())
            .zip(field_uses_default.iter())
            .zip(field_default_values.iter())
            .map(|((((ident, name), is_opt), uses_default), default_value)| {
                if *is_opt {
                    // Variable is Option<Option<T>>, unwrap to Option<T>
                    quote! {
                        #ident: #ident.unwrap_or(None)
                    }
                } else if let Some(default_tokens) = default_value {
                    // Variable is Option<Option<T>>; flatten collapses null → None
                    quote! {
                        #ident: #ident.flatten().unwrap_or_else(|| #default_tokens)
                    }
                } else if *uses_default {
                    // For types that implement Default: use Default::default() if missing
                    quote! {
                        #ident: #ident.unwrap_or_else(|| Default::default())
                    }
                } else {
                    // Required field: error if missing
                    quote! {
                        #ident: #ident.ok_or_else(|| serde::de::Error::missing_field(#name))?
                    }
                }
            });

        quote! {
            impl<'de> serde::Deserialize<'de> for #ident {
                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                where
                    D: serde::Deserializer<'de>,
                {
                    #[derive(serde::Deserialize)]
                    #[serde(field_identifier, rename_all = "snake_case")]
                    enum Field {
                        #(#deserialize_field_variants,)*
                        #[serde(other)]
                         Unknown,
                    }

                    struct #visitor_name;

                    impl<'de> serde::de::Visitor<'de> for #visitor_name {
                        type Value = #ident;

                        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                            formatter.write_str(concat!("struct ", stringify!(#ident)))
                        }

                        fn visit_map<V>(self, mut map: V) -> Result<#ident, V::Error>
                        where
                            V: serde::de::MapAccess<'de>,
                        {
                            #(#var_decls)*

                            while let Some(key) = map.next_key()? {
                                match key {
                                    #(#match_arms)*
                                    Field::Unknown => {
                                        let _: serde::de::IgnoredAny = map.next_value()?;
                                    }
                                }
                            }

                            Ok(#ident {
                                #meta_field_ident: #ousia::object::meta::Meta::default(),
                                #(#field_inits,)*
                            })
                        }
                    }

                    const FIELDS: &[&str] = &[#(#deserialize_field_names),*];
                    deserializer.deserialize_struct(stringify!(#ident), FIELDS, #visitor_name)
                }
            }
        }
    };

    // --- linkme manifest registration ---
    // Unique static name per type so two `OusiaObject` derives in the same
    // module never collide. The static is appended to `ousia::MANIFEST` at
    // link time; init_schema walks the slice to decide partitions.
    let manifest_static = format_ident!("__OUSIA_OBJECT_MANIFEST_{}", ident);

    // --- generate impl ---
    let expanded = quote! {
        #[#ousia::__linkme::distributed_slice(#ousia::MANIFEST)]
        #[linkme(crate = #ousia::__linkme)]
        #[allow(non_upper_case_globals)]
        static #manifest_static: #ousia::TypeManifestEntry = #ousia::TypeManifestEntry {
            kind: #ousia::ManifestKind::Object,
            type_name: #type_name,
            from_type: None,
            to_type: None,
        };

        impl #ousia::object::traits::Object for #ident {
            const TYPE: &'static str = #type_name;

            fn meta(&self) -> &#ousia::object::meta::Meta {
                &self.#meta_field_ident
            }

            fn meta_mut(&mut self) -> &mut #ousia::object::meta::Meta {
                &mut self.#meta_field_ident
            }

            fn index_meta(&self) -> #ousia::query::IndexMeta {
                let mut values = std::collections::BTreeMap::new();
                values.insert("created_at".to_string(), #ousia::query::ToIndexValue::to_index_value(&self.#meta_field_ident.created_at));
                values.insert("updated_at".to_string(), #ousia::query::ToIndexValue::to_index_value(&self.#meta_field_ident.updated_at));

                #(#index_meta_insertions)*
                #ousia::query::IndexMeta(values)
            }

            const HAS_GEO_FIELDS: bool = #has_geo_fields;

            fn geo_points(&self) -> Vec<#ousia::query::GeoPoint> {
                #geo_points_body
            }
        }

        impl #ousia::object::ObjectInternal for #ident {
            fn __serialize_internal(&self) -> ::std::vec::Vec<u8> {
                #internal_serialize_body
            }
        }

        impl #ident {
            #(#view_methods)*
        }

        impl #ousia::query::IndexQuery for #ident {
            fn indexed_fields() -> &'static [#ousia::query::IndexField] {
                &[ #(#index_fields),* ]
            }
        }

        #[derive(Debug)]
        pub struct #indexes_struct_name {
            pub created_at: #ousia::query::IndexField,
            pub updated_at: #ousia::query::IndexField,
            #(#indexes_struct_fields),*
        }

        impl #ident {
            pub const FIELDS: #indexes_struct_name = #indexes_struct_name {
                created_at: #ousia::query::IndexField {
                    name: "created_at",
                    kinds: &[#ousia::query::IndexKind::Search, #ousia::query::IndexKind::Sort],
                },
                updated_at: #ousia::query::IndexField {
                    name: "updated_at",
                    kinds: &[#ousia::query::IndexKind::Search, #ousia::query::IndexKind::Sort],
                },
                #(#indexes_const_fields),*
            };
        }

        #(#view_structs)*

        // Custom Serialize implementation (default view)
        impl serde::Serialize for #ident {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: serde::Serializer,
            {
                use serde::ser::SerializeStruct;
                let mut state = serializer.serialize_struct(stringify!(#ident), #field_count)?;
                #(#serialize_meta_fields)*
                #(#serialize_fields)*
                state.end()
            }
        }

        #deserialize_impl
    };

    Ok(TokenStream::from(expanded))
}
