// Copyright (C) 2026 Ordinary Labs, LLC.
//
// SPDX-License-Identifier: AGPL-3.0-only

use flexbuffers::BuilderOptions;
use hashbrown::HashMap;
use http::StatusCode;
use ordinary_action::{Action, ActionResult};
use ordinary_auth::Auth;
use ordinary_config::{
    ActionConfig, ActionFfi, ActionFfiSerialization, ActionFfiVersion, ActionTrigger, HttpMethod,
    StorageLimits,
};
use ordinary_storage::{
    Storage,
    saferlmdb::{self, EnvBuilder},
};
use ordinary_types::json_to_flexbuffer_vec;
use std::{error::Error, path::Path, sync::Arc};
use wasmtime::Engine;

#[tokio::test]
async fn integration() -> Result<(), Box<dyn Error>> {
    let store_dir = Path::new(".ordinary").join("store");

    if std::fs::read_dir(&store_dir).is_ok() {
        std::fs::remove_dir_all(&store_dir)?;
    }

    std::fs::create_dir_all(&store_dir)?;

    let env = Arc::new(unsafe {
        let mut env_builder = EnvBuilder::new()?;
        env_builder.set_maxreaders(126)?;
        env_builder.set_mapsize(16384 * 64 * 10)?;
        env_builder.set_maxdbs(13)?;
        env_builder.open(
            store_dir.to_str().expect("store dir is not str"),
            &saferlmdb::open::Flags::empty(),
            0o600,
        )?
    });

    let auth = Arc::new(Auth::new(
        "example.com".into(),
        None,
        [0u8; 32],
        env.clone(),
    )?);

    let model_configs = vec![];
    let content_defs = vec![];

    let storage = Arc::new(Storage::new(
        StorageLimits::default(),
        model_configs.clone(),
        content_defs.clone(),
        [0u8; 32],
        &env,
        store_dir.join("search"),
        false,
    )?);

    let mut model_map = HashMap::new();
    for model_config in model_configs {
        model_map.insert(model_config.name.clone(), model_config);
    }

    let mut content_map = HashMap::new();
    for content_def in content_defs {
        content_map.insert(content_def.name.clone(), content_def);
    }

    let integrations = Arc::new(vec![]);

    let config = ActionConfig {
        ffi: ActionFfi {
            version: ActionFfiVersion::V1,
            serialization: ActionFfiSerialization::FlexBufferVector,
        },
        idx: 0,
        name: "test".into(),
        lang: ordinary_config::ActionLang::Rust,
        dir_path: Some(".ordinary/test".into()),
        protected: None,
        access: vec![],
        accepts: ordinary_types::Kind::Json,
        returns: ordinary_types::Kind::Json,
        transactional: None,
        triggered_by: vec![ActionTrigger::Json {
            route: "/test".into(),
            method: HttpMethod::POST,
        }],
        timeout: None,
        cors: None,
        wasm_opt: None,
        privileged: None,
        variables: None,
    };

    let action = Action::new(
        None,
        Engine::default(),
        config,
        auth,
        storage,
        integrations,
        &model_map,
        &content_map,
        &None,
        None,
    )?;

    let mut builder = flexbuffers::Builder::new(&BuilderOptions::SHARE_NONE);
    let mut payload_vec = builder.start_vector();

    json_to_flexbuffer_vec(
        &action.config.accepts,
        &serde_json::Value::Array(vec![]),
        &mut payload_vec,
    )?;

    payload_vec.end_vector();

    let res = action.call(builder.view(), &Arc::new(vec![]))?;

    assert_eq!(
        res,
        ActionResult::StatusCode(StatusCode::SERVICE_UNAVAILABLE)
    );

    Ok(())
}
