//! Python-visible batch record types for all batch operations
//! (`batch_read`, `batch_operate`, `batch_remove`, `batch_write_numpy`).

use aerospike_core::BatchRecord;
use log::trace;
use pyo3::prelude::*;

use crate::errors::result_code_to_int;
use crate::types::key::key_to_py;
use crate::types::record::record_to_py_with_key;

/// A single record within batch results, exposed to Python.
#[pyclass(name = "BatchRecord")]
pub struct PyBatchRecord {
    #[pyo3(get)]
    key: Py<PyAny>,
    #[pyo3(get)]
    result: i32,
    #[pyo3(get)]
    record: Py<PyAny>,
}

/// Container holding a list of [`PyBatchRecord`]s, exposed to Python.
#[pyclass(name = "BatchRecords")]
pub struct PyBatchRecords {
    #[pyo3(get)]
    batch_records: Vec<Py<PyBatchRecord>>,
}

/// Convert a slice of `BatchRecord`s into a Python [`PyBatchRecords`] object.
pub fn batch_to_batch_records_py(
    py: Python<'_>,
    results: &[BatchRecord],
) -> PyResult<PyBatchRecords> {
    trace!("Converting {} batch records to Python", results.len());
    let mut batch_records = Vec::with_capacity(results.len());

    for br in results {
        let key_py = key_to_py(py, &br.key)?;

        let result_code = match &br.result_code {
            Some(rc) => result_code_to_int(rc),
            None => 0,
        };

        // Pass the already-converted key_py to avoid double key conversion
        let record_py = match &br.record {
            Some(record) => record_to_py_with_key(py, record, key_py.clone_ref(py))?,
            None => py.None(),
        };

        let batch_record = PyBatchRecord {
            key: key_py,
            result: result_code,
            record: record_py,
        };

        batch_records.push(Py::new(py, batch_record)?);
    }

    Ok(PyBatchRecords { batch_records })
}
