use std::{future::Future, pin::Pin};

use object_store::ObjectStoreExt;
use pyo3::prelude::*;
use pyo3_async_runtimes::tokio::get_runtime;
use pyo3_object_store::{PyObjectStore, PyObjectStoreError, PyObjectStoreResult, PyPath};

use crate::utils::PyNone;

#[pyfunction]
#[pyo3(signature = (store, from_, to, *, overwrite=true))]
pub(crate) fn rename(
    py: Python,
    store: PyObjectStore,
    from_: PyPath,
    to: PyPath,
    overwrite: bool,
) -> PyObjectStoreResult<()> {
    let runtime = get_runtime();
    let from_ = from_.into();
    let to = to.into();
    py.detach(|| {
        let fut: Pin<Box<dyn Future<Output = _> + Send>> = if overwrite {
            Box::pin(store.as_ref().rename(&from_, &to))
        } else {
            Box::pin(store.as_ref().rename_if_not_exists(&from_, &to))
        };
        runtime.block_on(fut)?;
        Ok::<_, PyObjectStoreError>(())
    })
}

#[pyfunction]
#[pyo3(signature = (store, from_, to, *, overwrite=true))]
pub(crate) fn rename_async(
    py: Python,
    store: PyObjectStore,
    from_: PyPath,
    to: PyPath,
    overwrite: bool,
) -> PyResult<Bound<PyAny>> {
    let from_ = from_.into();
    let to = to.into();
    pyo3_async_runtimes::tokio::future_into_py(py, async move {
        let fut: Pin<Box<dyn Future<Output = _> + Send>> = if overwrite {
            Box::pin(store.as_ref().rename(&from_, &to))
        } else {
            Box::pin(store.as_ref().rename_if_not_exists(&from_, &to))
        };
        fut.await.map_err(PyObjectStoreError::ObjectStoreError)?;
        Ok(PyNone)
    })
}
