use pyo3::prelude::*;
use pyo3::types::PyModule;
use noctahash::{noctahash, verify, VERSION};

#[pyfunction]
fn hash(
    password: &str,
    salt: Option<Vec<u8>>,
    time_cost: u32,
    memory_cost_mb: u32,
    parallelism: u32,
    encoding: &str,
) -> PyResult<String> {
    let salt_ref = salt.as_ref().map(|s| s.as_slice());
    noctahash(password, salt_ref, time_cost, memory_cost_mb, parallelism, encoding)
        .map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))
}

#[pyfunction]
fn verify_password(password: &str, hash_string: &str) -> bool {
    verify(password, hash_string)
}

#[pyfunction]
fn generate_salt(length: Option<usize>) -> PyResult<Vec<u8>> {
    use getrandom::getrandom;
    let len = length.unwrap_or(32);
    let mut salt = vec![0u8; len];
    getrandom(&mut salt).map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!("Failed to generate salt: {}", e)))?;
    Ok(salt)
}

#[pyfunction]
fn get_version() -> u32 {
    VERSION
}

#[pyfunction]
fn get_default_params() -> PyResult<&'static str> {
    Ok(r#"{"time_cost":3,"memory_cost_mb":64,"parallelism":4}"#)
}

#[pymodule]
fn noctahash_py(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(hash, m)?)?;
    m.add_function(wrap_pyfunction!(verify_password, m)?)?;
    m.add_function(wrap_pyfunction!(generate_salt, m)?)?;
    m.add_function(wrap_pyfunction!(get_version, m)?)?;
    m.add_function(wrap_pyfunction!(get_default_params, m)?)?;
    m.add("__version__", env!("CARGO_PKG_VERSION"))?;
    Ok(())
}
