#!/usr/bin/env node
// Test script for mixed-content message testing
// Tests sending a mix of text, json, table, image, audio, video, and binary data
// from JavaScript serviceA to JavaScript serviceB using NATSBridge.js smartsend
//
// This test demonstrates that any combination and any number of mixed content
// can be sent and received correctly.

const { smartsend, uuid4, log_trace, _serialize_data } = require('./src/NATSBridge');

// Configuration
const SUBJECT = "/NATSBridge_mix_test";
const NATS_URL = "nats.yiem.cc";
const FILESERVER_URL = "http://192.168.88.104:8080";

// Create correlation ID for tracing
const correlation_id = uuid4();

// Helper: Log with correlation ID
function log_trace(message) {
    const timestamp = new Date().toISOString();
    console.log(`[${timestamp}] [Correlation: ${correlation_id}] ${message}`);
}

// File upload handler for plik server
async function plik_upload_handler(fileserver_url, dataname, data, correlation_id) {
    log_trace(correlation_id, `Uploading ${dataname} to fileserver: ${fileserver_url}`);
    
    // Step 1: Get upload ID and token
    const url_getUploadID = `${fileserver_url}/upload`;
    const headers = {
        "Content-Type": "application/json"
    };
    const body = JSON.stringify({ OneShot: true });
    
    let response = await fetch(url_getUploadID, {
        method: "POST",
        headers: headers,
        body: body
    });
    
    if (!response.ok) {
        throw new Error(`Failed to get upload ID: ${response.status} ${response.statusText}`);
    }
    
    const responseJson = await response.json();
    const uploadid = responseJson.id;
    const uploadtoken = responseJson.uploadToken;
    
    // Step 2: Upload file data
    const url_upload = `${fileserver_url}/file/${uploadid}`;
    
    // Create multipart form data
    const formData = new FormData();
    const blob = new Blob([data], { type: "application/octet-stream" });
    formData.append("file", blob, dataname);
    
    response = await fetch(url_upload, {
        method: "POST",
        headers: {
            "X-UploadToken": uploadtoken
        },
        body: formData
    });
    
    if (!response.ok) {
        throw new Error(`Failed to upload file: ${response.status} ${response.statusText}`);
    }
    
    const fileResponseJson = await response.json();
    const fileid = fileResponseJson.id;
    
    // Build the download URL
    const url = `${fileserver_url}/file/${uploadid}/${fileid}/${encodeURIComponent(dataname)}`;
    
    log_trace(correlation_id, `Uploaded to URL: ${url}`);
    
    return {
        status: response.status,
        uploadid: uploadid,
        fileid: fileid,
        url: url
    };
}

// Helper: Create sample data for each type
function create_sample_data() {
    // Text data (small - direct transport)
    const text_data = "Hello! This is a test chat message. 🎉\nHow are you doing today? 😊";
    
    // Dictionary/JSON data (medium - could be direct or link)
    const dict_data = {
        type: "chat",
        sender: "serviceA",
        receiver: "serviceB",
        metadata: {
            timestamp: new Date().toISOString(),
            priority: "high",
            tags: ["urgent", "chat", "test"]
        },
        content: {
            text: "This is a JSON-formatted chat message with nested structure.",
            format: "markdown",
            mentions: ["user1", "user2"]
        }
    };
    
    // Table data (small - direct transport) - NOT IMPLEMENTED (requires apache-arrow)
    // const table_data_small = {...};
    
    // Table data (large - link transport) - NOT IMPLEMENTED (requires apache-arrow)
    // const table_data_large = {...};
    
    // Image data (small binary - direct transport)
    // Create a simple 10x10 pixel PNG-like data
    const image_width = 10;
    const image_height = 10;
    let image_data = new Uint8Array(128);  // PNG header + pixel data
    // PNG header
    image_data[0] = 0x89;
    image_data[1] = 0x50;
    image_data[2] = 0x4E;
    image_data[3] = 0x47;
    image_data[4] = 0x0D;
    image_data[5] = 0x0A;
    image_data[6] = 0x1A;
    image_data[7] = 0x0A;
    // Simple RGB data (10*10*3 = 300 bytes)
    for (let i = 0; i < 300; i++) {
        image_data[i + 8] = 0xFF;  // Red pixel
    }
    
    // Image data (large - link transport)
    const large_image_width = 500;
    const large_image_height = 1000;
    const large_image_data = new Uint8Array(large_image_width * large_image_height * 3 + 8);
    // PNG header
    large_image_data[0] = 0x89;
    large_image_data[1] = 0x50;
    large_image_data[2] = 0x4E;
    large_image_data[3] = 0x47;
    large_image_data[4] = 0x0D;
    large_image_data[5] = 0x0A;
    large_image_data[6] = 0x1A;
    large_image_data[7] = 0x0A;
    // Random RGB data
    for (let i = 0; i < large_image_width * large_image_height * 3; i++) {
        large_image_data[i + 8] = Math.floor(Math.random() * 255);
    }
    
    // Audio data (small binary - direct transport)
    const audio_data = new Uint8Array(100);
    for (let i = 0; i < 100; i++) {
        audio_data[i] = Math.floor(Math.random() * 255);
    }
    
    // Audio data (large - link transport)
    const large_audio_data = new Uint8Array(1_500_000);
    for (let i = 0; i < 1_500_000; i++) {
        large_audio_data[i] = Math.floor(Math.random() * 255);
    }
    
    // Video data (small binary - direct transport)
    const video_data = new Uint8Array(150);
    for (let i = 0; i < 150; i++) {
        video_data[i] = Math.floor(Math.random() * 255);
    }
    
    // Video data (large - link transport)
    const large_video_data = new Uint8Array(1_500_000);
    for (let i = 0; i < 1_500_000; i++) {
        large_video_data[i] = Math.floor(Math.random() * 255);
    }
    
    // Binary data (small - direct transport)
    const binary_data = new Uint8Array(200);
    for (let i = 0; i < 200; i++) {
        binary_data[i] = Math.floor(Math.random() * 255);
    }
    
    // Binary data (large - link transport)
    const large_binary_data = new Uint8Array(1_500_000);
    for (let i = 0; i < 1_500_000; i++) {
        large_binary_data[i] = Math.floor(Math.random() * 255);
    }
    
    return {
        text_data,
        dict_data,
        // table_data_small,
        // table_data_large,
        image_data,
        large_image_data,
        audio_data,
        large_audio_data,
        video_data,
        large_video_data,
        binary_data,
        large_binary_data
    };
}

// Sender: Send mixed content via smartsend
async function test_mix_send() {
    // Create sample data
    const { text_data, dict_data, image_data, large_image_data, audio_data, large_audio_data, video_data, large_video_data, binary_data, large_binary_data } = create_sample_data();
    
    // Create payloads list - mixed content with both small and large data
    // Small data uses direct transport, large data uses link transport
    const payloads = [
        // Small data (direct transport) - text, dictionary
        { dataname: "chat_text", data: text_data, type: "text" },
        { dataname: "chat_json", data: dict_data, type: "dictionary" },
        // { dataname: "chat_table_small", data: table_data_small, type: "table" },
        
        // Large data (link transport) - large image, large audio, large video, large binary
        // { dataname: "chat_table_large", data: table_data_large, type: "table" },
        { dataname: "user_image_large", data: large_image_data, type: "image" },
        { dataname: "audio_clip_large", data: large_audio_data, type: "audio" },
        { dataname: "video_clip_large", data: large_video_data, type: "video" },
        { dataname: "binary_file_large", data: large_binary_data, type: "binary" }
    ];
    
    // Use smartsend with mixed content
    const env = await smartsend(
        SUBJECT,
        payloads,
        {
            natsUrl: NATS_URL,
            fileserverUrl: FILESERVER_URL,
            fileserverUploadHandler: plik_upload_handler,
            sizeThreshold: 1_000_000,
            correlationId: correlation_id,
            msgPurpose: "chat",
            senderName: "mix_sender",
            receiverName: "",
            receiverId: "",
            replyTo: "",
            replyToMsgId: ""
        }
    );
    
    log_trace(`Sent message with ${env.payloads.length} payloads`);
    
    // Log transport type for each payload
    for (let i = 0; i < env.payloads.length; i++) {
        const payload = env.payloads[i];
        log_trace(`Payload ${i + 1} ('${payload.dataname}'):`);
        log_trace(`  Transport: ${payload.transport}`);
        log_trace(`  Type: ${payload.type}`);
        log_trace(`  Size: ${payload.size} bytes`);
        log_trace(`  Encoding: ${payload.encoding}`);
        
        if (payload.transport === "link") {
            log_trace(`  URL: ${payload.data}`);
        }
    }
    
    // Summary
    console.log("\n--- Transport Summary ---");
    const direct_count = env.payloads.filter(p => p.transport === "direct").length;
    const link_count = env.payloads.filter(p => p.transport === "link").length;
    log_trace(`Direct transport: ${direct_count} payloads`);
    log_trace(`Link transport: ${link_count} payloads`);
}

// Run the test
console.log("Starting mixed-content transport test...");
console.log(`Correlation ID: ${correlation_id}`);

// Run sender
console.log("start smartsend for mixed content");
test_mix_send();

console.log("\nTest completed.");
console.log("Note: Run test_js_to_js_mix_receiver.js to receive the messages.");