// r8r: rust port of n8n.io
// Initial author: Michael Cochran <mcochran@cochranblock.org>
// Built for: Tanner Woodrum, intended cofounder
// License: Unlicense (public domain dedication, see UNLICENSE)
//
// `read_binary_file` — read a file from disk and emit it as a single item
// with the bytes attached as binary data + metadata.

use async_trait::async_trait;
use crate::core::error::NodeError;
use crate::core::types::*;
use crate::engine::{ExecuteCtx, Node, NodeFactory};
use serde_json::json;
use std::collections::HashMap;
use std::sync::Arc;

pub struct ReadBinaryFileNode;

static META: NodeMetadata = NodeMetadata {
    name: "read_binary_file",
    display_name: "Read Binary File",
    version: &[1],
    group: &["transform"],
    description: "Read a file from disk into binary data + metadata",
    inputs: 1,
    outputs: 1,
    properties: &[],
    credentials: &[],
};

#[async_trait]
impl Node for ReadBinaryFileNode {
    fn metadata(&self) -> &'static NodeMetadata { &META }

    async fn execute(&self, ctx: &mut ExecuteCtx<'_>) -> Result<NodeOutput, NodeError> {
        let path = ctx.param_str("path")?;
        let key = ctx.node_def.parameters.get("binary_key")
            .and_then(|v| v.as_str()).unwrap_or("data").to_string();
        let bytes = tokio::fs::read(&path).await
            .map_err(|e| NodeError::Other(format!("read_binary_file: {}: {}", path, e)))?;
        let mime = mime_guess::from_path(&path).first_or_octet_stream().to_string();
        let file_name = std::path::Path::new(&path).file_name()
            .map(|f| f.to_string_lossy().into_owned());
        let size = bytes.len();

        let mut binary = HashMap::new();
        binary.insert(key.clone(), BinaryData {
            mime_type: mime.clone(),
            file_name: file_name.clone(),
            data: bytes,
        });

        let item = NodeItem {
            json: json!({
                "path": path,
                "size": size,
                "mime_type": mime,
                "file_name": file_name,
                "binary_key": key,
            }),
            binary: Some(binary),
            ..Default::default()
        };
        Ok(vec![vec![item]])
    }
}

inventory::submit! { NodeFactory::new("read_binary_file", || Arc::new(ReadBinaryFileNode)) }
