/// Entry for creating {{ model_name }}.
#[derive(Debug, Clone)]
pub struct {{ entry_name }} {
{%- for field in create_fields %}
    pub {{ field.name }}: {{ field.rust_type }},
{%- endfor %}
}

impl {{ entry_name }} {
    pub(crate) fn to_engine_data(&self) -> serde_json::Value {
        let mut data = serde_json::Map::new();
{%- for field in create_fields %}
        data.insert(
            "{{ field.db_name }}".to_string(),
{%- if field.is_optional %}
            match &self.{{ field.name }} {
                Some(value) => nautilus_core::Value::from(value.clone()).to_json_plain(),
                None => serde_json::Value::Null,
            },
{%- else %}
            nautilus_core::Value::from(self.{{ field.name }}.clone()).to_json_plain(),
{%- endif %}
        );
{%- endfor %}
        serde_json::Value::Object(data)
    }
}

/// Internal CreateMany builder for {{ model_name }} — use `{{ delegate_name }}::create_many(entries)` instead.
pub(crate) struct {{ create_many_name }}<E: crate::Executor> {
    client: crate::Client<E>,
    entries: Vec<{{ entry_name }}>,
}

impl<E> {{ create_many_name }}<E>
where
    E: crate::Executor,
    for<'a> E::Row<'a>: Into<crate::Row>,
{
    pub(crate) fn new(client: crate::Client<E>) -> Self {
        {{ create_many_name }} {
            client,
            entries: vec![],
        }
    }

    /// Add an entry to the batch.
    #[must_use]
    pub(crate) fn entry(mut self, entry: {{ entry_name }}) -> Self {
        self.entries.push(entry);
        self
    }

    /// Execute the batch create using a single multi-row `INSERT`.
    pub(crate) async fn exec(self) -> nautilus_core::Result<Vec<{{ model_name }}>> {
        use nautilus_core::*;
        use std::convert::Into;

        if self.entries.is_empty() {
            return Ok(vec![]);
        }

        // MySQL does not support RETURNING — fall back to per-row inserts.
        if !self.client.dialect().supports_returning() {
            let mut results = Vec::with_capacity(self.entries.len());
            for entry in self.entries {
                let result = {{ create_name }}::new(self.client.clone())
{%- for field in create_fields %}
                    .{{ field.name }}(entry.{{ field.name }})
{%- endfor %}
                    .exec().await?;
                results.push(result);
            }
            return Ok(results);
        }

        let columns = vec![
{%- for field in create_fields %}
            ColumnMarker::from_static("{{ table_name }}", "{{ field.db_name }}"),
{%- endfor %}
        ];

        let mut rows = Vec::with_capacity(self.entries.len());
        for entry in &self.entries {
            let row = vec![
{%- for field in create_fields %}
                Value::from(entry.{{ field.name }}.clone()),
{%- endfor %}
            ];
            rows.push(row);
        }

        let returning_cols = vec![
{%- for field in all_scalar_fields %}
            ColumnMarker::from_static("{{ table_name }}", "{{ field.db_name }}"),
{%- endfor %}
        ];
        let builder = Insert::into_table("{{ table_name }}")
            .with_capacity(InsertCapacity {
                columns: columns.len(),
                rows: rows.len(),
                returning: returning_cols.len(),
            })
            .columns(columns)
            .rows(rows)
            .returning(returning_cols);

        let insert = builder.build()?;
        let sql = self.client.dialect().render_insert_owned(insert)?;

        let rows = crate::execute_all(self.client.executor(), &sql)
            .await
            .map_err(|e| Error::Other(e.to_string()))?;

        let mut results = Vec::with_capacity(rows.len());
        for row in rows {
            let row: crate::Row = row.into();
            let decoded = decode_model_row_with_hints(
                row,
                all_scalar_decode_slots(),
                all_scalar_value_hints(),
            )?;
            results.push(decoded);
        }

        Ok(results)
    }
}
