//! Default decoded-texture provider for the avatar baking pipeline.

use crate::client_core::ClientWeakHandle;
use crate::{Error, GridClient, IBakingTextureProvider};
use libremetaverse_types::UUID;
use libremetaverse_types::compat::CancellationToken;
use std::future::Future;
use std::pin::Pin;

pub struct GridClientBakingTextureProvider {
    client: ClientWeakHandle,
}

impl GridClientBakingTextureProvider {
    #[allow(clippy::needless_pass_by_value, clippy::unnecessary_wraps)]
    // The generated constructor owns its GridClient argument and uses the shared Result model.
    pub(crate) fn native_new(client: GridClient) -> Result<Self, Error> {
        Ok(Self {
            client: client.native_weak_handle(),
        })
    }

    pub(crate) async fn native_request_texture(
        &self,
        texture_id: UUID,
        cancellation_token: Option<CancellationToken>,
    ) -> Result<Option<crate::assets::AssetTexture>, Error> {
        let token = cancellation_token.unwrap_or_default();
        token.throw_if_cancellation_requested()?;
        let client = self.client.upgrade().ok_or(Error::InvalidOperation)?;
        let Some(mut texture) = client
            .native_assets()?
            .request_image(texture_id, None, Some(token.clone()))
            .await?
        else {
            return Ok(None);
        };
        token.throw_if_cancellation_requested()?;
        if texture.native_decode_image()? {
            Ok(Some(texture))
        } else {
            Ok(None)
        }
    }
}

impl IBakingTextureProvider for GridClientBakingTextureProvider {
    fn request_texture(
        &self,
        texture_id: UUID,
        cancellation_token: Option<CancellationToken>,
    ) -> Pin<Box<dyn Future<Output = Result<Option<crate::assets::AssetTexture>, Error>> + Send + '_>>
    {
        Box::pin(self.native_request_texture(texture_id, cancellation_token))
    }
}
