//! Function that are can be usefull on the python side.

use pyo3::prelude::*;
use pyo3::types::PyBytes;

use std::io::Cursor;
use std::path::PathBuf;

use crate::Result;
use androscalpel_serializer::{Serializable, Sleb128, Uleb128, Uleb128p1};

/// Convert an integer to the uleb128 byte encoding
#[pyfunction]
pub fn int_to_uleb128(py: Python, x: u32) -> Result<PyObject> {
    Ok(PyBytes::new(py, &Uleb128(x).serialize_to_vec()?).into())
}

/// Convert an integer to the uleb128p1 byte encoding
#[pyfunction]
pub fn int_to_uleb128p1(py: Python, x: u32) -> Result<PyObject> {
    Ok(PyBytes::new(py, &Uleb128p1(x).serialize_to_vec()?).into())
}
/// Convert an integer to the sleb128 byte encoding
#[pyfunction]
pub fn int_to_sleb128(py: Python, x: i32) -> Result<PyObject> {
    Ok(PyBytes::new(py, &Sleb128(x).serialize_to_vec()?).into())
}

/// Decode an uleb128 encoded integer
#[pyfunction]
pub fn uleb128_to_int(b: &[u8]) -> Result<u32> {
    Ok(Uleb128::deserialize_from_slice(b)?.0)
}

/// Decode an uleb128p1 encoded integer
#[pyfunction]
pub fn uleb128p1_to_int(b: &[u8]) -> Result<u32> {
    Ok(Uleb128p1::deserialize_from_slice(b)?.0)
}

/// Decode an sleb128 encoded integer
#[pyfunction]
pub fn sleb128_to_int(b: &[u8]) -> Result<i32> {
    Ok(Sleb128::deserialize_from_slice(b)?.0)
}

/// Replace the dex files a an apk an resigned the apk.
///
/// # Warning
///
/// For now, only jks keystore are allowed.
///
/// The `zipalign` and `apksigner` args allow to use a specific version of the
/// tools instead of the one in the PATH (if it even exist)
#[pyfunction]
pub fn replace_dex(
    apk: PathBuf,
    dst: PathBuf,
    dexfiles: Vec<&[u8]>,
    keystore: PathBuf,
    zipalign: Option<PathBuf>,
    apksigner: Option<PathBuf>,
) {
    let mut dexfiles: Vec<_> = dexfiles.iter().map(Cursor::new).collect();
    apk_frauder::replace_dex(apk, dst, &mut dexfiles, keystore, zipalign, apksigner)
}

/// export the function in a python module
pub(crate) fn export_module(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(int_to_uleb128, m)?)?;
    m.add_function(wrap_pyfunction!(int_to_uleb128p1, m)?)?;
    m.add_function(wrap_pyfunction!(int_to_sleb128, m)?)?;
    m.add_function(wrap_pyfunction!(uleb128_to_int, m)?)?;
    m.add_function(wrap_pyfunction!(uleb128p1_to_int, m)?)?;
    m.add_function(wrap_pyfunction!(sleb128_to_int, m)?)?;
    m.add_function(wrap_pyfunction!(replace_dex, m)?)?;
    Ok(())
}
