// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

use perspective_js::utils::ApiResult;
use wasm_bindgen::JsValue;

/// An extension method for converting various [`js_sys`] and [`web_sys`] types
/// to [`web_sys::Blob`].
pub trait AsBlob {
    /// Standardized conversions from common [`wasm_bindgen`] types to
    /// [`web_sys::Blob`], which is commonly necessary to provide data to a
    /// download or clipboard action.
    fn as_blob(&self) -> ApiResult<web_sys::Blob>;
}

impl AsBlob for js_sys::ArrayBuffer {
    fn as_blob(&self) -> ApiResult<web_sys::Blob> {
        let array = std::iter::once(js_sys::Uint8Array::new(self)).collect::<js_sys::Array>();
        Ok(web_sys::Blob::new_with_u8_array_sequence(&array)?)
    }
}

impl AsBlob for JsValue {
    fn as_blob(&self) -> ApiResult<web_sys::Blob> {
        let array = std::iter::once(self).collect::<js_sys::Array>();
        let options = web_sys::BlobPropertyBag::new();
        options.set_type("text/plain");
        Ok(web_sys::Blob::new_with_str_sequence_and_options(
            &array, &options,
        )?)
    }
}

impl AsBlob for js_sys::JsString {
    fn as_blob(&self) -> ApiResult<web_sys::Blob> {
        let array = std::iter::once(self).collect::<js_sys::Array>();
        let options = web_sys::BlobPropertyBag::new();
        options.set_type("text/plain");
        Ok(web_sys::Blob::new_with_str_sequence_and_options(
            &array, &options,
        )?)
    }
}

impl AsBlob for js_sys::Object {
    fn as_blob(&self) -> ApiResult<web_sys::Blob> {
        let array = std::iter::once(js_sys::JSON::stringify(self)?).collect::<js_sys::Array>();
        let options = web_sys::BlobPropertyBag::new();
        options.set_type("text/plain");
        Ok(web_sys::Blob::new_with_str_sequence_and_options(
            &array, &options,
        )?)
    }
}
