use std::collections::HashMap;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    pub type KV;

    #[wasm_bindgen(catch, js_name = "get", static_method_of = KV)]
    pub async fn get(key: JsValue, r#type: JsValue) -> Result<JsValue, JsValue>;

    #[wasm_bindgen(catch, js_name = "getWithMetadata", static_method_of = KV)]
    pub async fn get_with_metadata(key: JsValue, r#type: JsValue) -> Result<JsValue, JsValue>;

    #[wasm_bindgen(catch, js_name = "put", static_method_of = KV)]
    pub async fn put(key: JsValue, value: JsValue, options: JsValue) -> Result<(), JsValue>;

    #[wasm_bindgen(catch, js_name = "delete", static_method_of = KV)]
    pub async fn delete(key: JsValue) -> Result<(), JsValue>;

    #[wasm_bindgen(catch, js_name = "list", static_method_of = KV)]
    pub async fn list(options: JsValue) -> Result<JsValue, JsValue>;
}

pub struct Implementation;

impl Implementation {
    pub async fn get<T: From<JsValue>>(
        key: &str,
        r#type: Option<Type>,
    ) -> Result<Option<T>, Error> {
        Err(Error)
    }

    pub async fn get_with_metadata<T: From<JsValue>>(
        key: &str,
        r#type: Option<Type>,
    ) -> Result<Option<T>, Error> {
        Err(Error)
    }

    pub async fn put<Value: Into<JsValue>>(
        key: &str,
        value: Value,
        options: Option<PutOptions>,
    ) -> Result<(), Error> {
        Err(Error)
    }

    pub async fn delete(key: &str) -> Result<(), Error> {
        Err(Error)
    }

    pub async fn list(options: Option<ListOptions>) -> Result<ListValue, Error> {
        Err(Error)
    }
}

pub enum Type {
    Text,
    JSON,
    ArrayBuffer,
    Stream,
}

pub struct PutOptions {
    pub expiration: Option<u64>,
    pub expiration_ttl: Option<u64>,
    pub metadata: Option<Metadata>,
}

pub struct ListOptions {
    pub prefix: Option<&'static str>,
    pub limit: Option<u64>,
    pub cursor: Option<&'static str>,
}

pub struct ListValue {
    pub keys: Vec<ListValueKey>,
    pub list_complete: bool,
    pub cursor: Option<&'static str>,
}

pub struct ListValueKey {
    pub name: &'static str,
    pub expiration: Option<u64>,
    pub metadata: Option<Metadata>,
}

pub type Metadata = HashMap<&'static str, serde_json::Value>;

pub struct Error;
