//! Memvid v2 Memory wrapper for Python
//!
//! Wraps memvid-core::memvid::Memvid with PyO3 bindings

use memvid_core::memvid::Memvid;
use pyo3::exceptions::{PyIOError, PyValueError};
use pyo3::prelude::*;
use std::io::Read;
use std::path::PathBuf;

/// Python-facing Memory class wrapping memvid-core
#[pyclass]
pub struct MemvidMemory {
    inner: Memvid,
    path: PathBuf,
}

#[pymethods]
impl MemvidMemory {
    /// Create a new memory file at the given path
    #[staticmethod]
    fn create(path: String) -> PyResult<Self> {
        let path_buf = PathBuf::from(&path);
        let memvid = Memvid::create(&path_buf)
            .map_err(|e| PyIOError::new_err(format!("Failed to create memory: {}", e)))?;
        Ok(Self {
            inner: memvid,
            path: path_buf,
        })
    }

    /// Open an existing memory file
    #[staticmethod]
    fn open(path: String) -> PyResult<Self> {
        let path_buf = PathBuf::from(&path);
        let memvid = Memvid::open(&path_buf)
            .map_err(|e| PyIOError::new_err(format!("Failed to open memory: {}", e)))?;
        Ok(Self {
            inner: memvid,
            path: path_buf,
        })
    }

    /// Append text content to memory and return the 0-based frame index
    fn append(&mut self, content: String) -> PyResult<u64> {
        // put_bytes returns 1-based ID, convert to 0-based index for consistency
        let frame_id = self
            .inner
            .put_bytes(content.as_bytes())
            .map_err(|e| PyValueError::new_err(format!("Failed to append: {}", e)))?;
        // Return 0-based index (frame_id - 1)
        Ok(frame_id.saturating_sub(1))
    }

    /// Commit pending writes to disk
    fn commit(&mut self) -> PyResult<()> {
        self.inner
            .commit()
            .map_err(|e| PyIOError::new_err(format!("Failed to commit: {}", e)))
    }

    /// Get frame content by 0-based index
    fn get_frame(&mut self, index: u64) -> PyResult<String> {
        let mut reader = self
            .inner
            .blob_reader(index)
            .map_err(|e| PyValueError::new_err(format!("Failed to get frame reader: {}", e)))?;

        let mut buf = Vec::new();
        reader
            .read_to_end(&mut buf)
            .map_err(|e| PyValueError::new_err(format!("Failed to read frame: {}", e)))?;

        String::from_utf8(buf)
            .map_err(|e| PyValueError::new_err(format!("Invalid UTF-8 in frame: {}", e)))
    }

    /// Get total frame count
    fn frame_count(&self) -> usize {
        self.inner.frame_count()
    }

    fn __repr__(&self) -> String {
        format!(
            "MemvidMemory(path='{}', frames={})",
            self.path.display(),
            self.inner.frame_count()
        )
    }
}
