// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! Generate cross-platform test vectors for bincode serialization.
//!
//! This script generates deterministic test vectors to verify that
//! the TypeScript and Rust bincode implementations produce identical results.

use std::fs;

use serde::{Deserialize, Serialize};

// ========== Test Vector Structures ==========

#[derive(Debug, Serialize)]
struct TestVectors {
    version: String,
    vectors: Vectors,
}

#[derive(Debug, Serialize)]
struct Vectors {
    primitives: Vec<PrimitiveVector>,
    strings_and_bytes: Vec<StringBytesVector>,
    collections: Vec<CollectionVector>,
    options: Vec<OptionVector>,
    structs: Vec<StructVector>,
    enums: Vec<EnumVector>,
    fixed_arrays: Vec<FixedArrayVector>,
    instruction_patterns: Vec<InstructionVector>,
}

#[derive(Debug, Serialize)]
struct PrimitiveVector {
    id: String,
    description: String,
    #[serde(rename = "type")]
    type_name: String,
    input_value: serde_json::Value,
    expected_hex: String,
}

#[derive(Debug, Serialize)]
struct StringBytesVector {
    id: String,
    description: String,
    #[serde(rename = "type")]
    type_name: String,
    input_value: String,
    expected_hex: String,
}

#[derive(Debug, Serialize)]
struct CollectionVector {
    id: String,
    description: String,
    #[serde(rename = "type")]
    type_name: String,
    element_type: String,
    input_value: serde_json::Value,
    expected_hex: String,
}

#[derive(Debug, Serialize)]
struct OptionVector {
    id: String,
    description: String,
    inner_type: String,
    is_some: bool,
    input_value: serde_json::Value,
    expected_hex: String,
}

#[derive(Debug, Serialize)]
struct StructVector {
    id: String,
    description: String,
    schema: Vec<FieldDef>,
    input_value: serde_json::Value,
    expected_hex: String,
}

#[derive(Debug, Serialize)]
struct FieldDef {
    name: String,
    #[serde(rename = "type")]
    type_name: String,
}

#[derive(Debug, Serialize)]
struct EnumVector {
    id: String,
    description: String,
    variants: Vec<VariantDef>,
    input_variant: String,
    input_value: serde_json::Value,
    expected_hex: String,
}

#[derive(Debug, Clone, Serialize)]
struct VariantDef {
    name: String,
    #[serde(rename = "type")]
    type_name: Option<String>,
}

#[derive(Debug, Serialize)]
struct FixedArrayVector {
    id: String,
    description: String,
    length: usize,
    input_hex: String,
    expected_hex: String,
}

#[derive(Debug, Serialize)]
struct InstructionVector {
    id: String,
    description: String,
    schema: Vec<FieldDef>,
    input_value: serde_json::Value,
    expected_hex: String,
}

// ========== Helper Functions ==========

fn bytes_to_hex(bytes: &[u8]) -> String {
    bytes.iter().map(|b| format!("{:02x}", b)).collect()
}

// ========== Rust Types for Serialization ==========

#[derive(Debug, Serialize, Deserialize)]
struct Point {
    x: i32,
    y: i32,
}

#[derive(Debug, Serialize, Deserialize)]
struct Line {
    start: Point,
    end: Point,
}

#[derive(Debug, Serialize, Deserialize)]
struct TransferData {
    amount: u64,
    memo: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
enum Status {
    Active,
    Pending(u32),
    Error(String),
}

#[derive(Debug, Serialize, Deserialize)]
enum SimpleEnum {
    A,
    B,
    C,
}

// ========== Vector Generators ==========

#[allow(clippy::vec_init_then_push)]
fn generate_primitive_vectors() -> Vec<PrimitiveVector> {
    let mut vectors = Vec::new();

    // u8
    vectors.push(PrimitiveVector {
        id: "u8_zero".to_string(),
        description: "u8 value 0".to_string(),
        type_name: "u8".to_string(),
        input_value: serde_json::json!(0),
        expected_hex: bytes_to_hex(&bincode::serialize(&0u8).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "u8_max".to_string(),
        description: "u8 value 255 (max)".to_string(),
        type_name: "u8".to_string(),
        input_value: serde_json::json!(255),
        expected_hex: bytes_to_hex(&bincode::serialize(&255u8).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "u8_42".to_string(),
        description: "u8 value 42".to_string(),
        type_name: "u8".to_string(),
        input_value: serde_json::json!(42),
        expected_hex: bytes_to_hex(&bincode::serialize(&42u8).unwrap()),
    });

    // u16
    vectors.push(PrimitiveVector {
        id: "u16_zero".to_string(),
        description: "u16 value 0".to_string(),
        type_name: "u16".to_string(),
        input_value: serde_json::json!(0),
        expected_hex: bytes_to_hex(&bincode::serialize(&0u16).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "u16_max".to_string(),
        description: "u16 value 65535 (max)".to_string(),
        type_name: "u16".to_string(),
        input_value: serde_json::json!(65535),
        expected_hex: bytes_to_hex(&bincode::serialize(&65535u16).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "u16_0x1234".to_string(),
        description: "u16 value 0x1234 (little-endian test)".to_string(),
        type_name: "u16".to_string(),
        input_value: serde_json::json!(0x1234),
        expected_hex: bytes_to_hex(&bincode::serialize(&0x1234u16).unwrap()),
    });

    // u32
    vectors.push(PrimitiveVector {
        id: "u32_zero".to_string(),
        description: "u32 value 0".to_string(),
        type_name: "u32".to_string(),
        input_value: serde_json::json!(0),
        expected_hex: bytes_to_hex(&bincode::serialize(&0u32).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "u32_max".to_string(),
        description: "u32 value 4294967295 (max)".to_string(),
        type_name: "u32".to_string(),
        input_value: serde_json::json!(4294967295u64),
        expected_hex: bytes_to_hex(&bincode::serialize(&4294967295u32).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "u32_0x12345678".to_string(),
        description: "u32 value 0x12345678 (little-endian test)".to_string(),
        type_name: "u32".to_string(),
        input_value: serde_json::json!(0x12345678u32),
        expected_hex: bytes_to_hex(&bincode::serialize(&0x12345678u32).unwrap()),
    });

    // u64
    vectors.push(PrimitiveVector {
        id: "u64_zero".to_string(),
        description: "u64 value 0".to_string(),
        type_name: "u64".to_string(),
        input_value: serde_json::json!("0"),
        expected_hex: bytes_to_hex(&bincode::serialize(&0u64).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "u64_1_billion".to_string(),
        description: "u64 value 1000000000 (1 billion, typical SOL amount)".to_string(),
        type_name: "u64".to_string(),
        input_value: serde_json::json!("1000000000"),
        expected_hex: bytes_to_hex(&bincode::serialize(&1_000_000_000u64).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "u64_max".to_string(),
        description: "u64 max value".to_string(),
        type_name: "u64".to_string(),
        input_value: serde_json::json!("18446744073709551615"),
        expected_hex: bytes_to_hex(&bincode::serialize(&u64::MAX).unwrap()),
    });

    // i8
    vectors.push(PrimitiveVector {
        id: "i8_zero".to_string(),
        description: "i8 value 0".to_string(),
        type_name: "i8".to_string(),
        input_value: serde_json::json!(0),
        expected_hex: bytes_to_hex(&bincode::serialize(&0i8).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "i8_negative_1".to_string(),
        description: "i8 value -1".to_string(),
        type_name: "i8".to_string(),
        input_value: serde_json::json!(-1),
        expected_hex: bytes_to_hex(&bincode::serialize(&(-1i8)).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "i8_min".to_string(),
        description: "i8 min value -128".to_string(),
        type_name: "i8".to_string(),
        input_value: serde_json::json!(-128),
        expected_hex: bytes_to_hex(&bincode::serialize(&i8::MIN).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "i8_max".to_string(),
        description: "i8 max value 127".to_string(),
        type_name: "i8".to_string(),
        input_value: serde_json::json!(127),
        expected_hex: bytes_to_hex(&bincode::serialize(&i8::MAX).unwrap()),
    });

    // i16
    vectors.push(PrimitiveVector {
        id: "i16_negative_1".to_string(),
        description: "i16 value -1".to_string(),
        type_name: "i16".to_string(),
        input_value: serde_json::json!(-1),
        expected_hex: bytes_to_hex(&bincode::serialize(&(-1i16)).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "i16_min".to_string(),
        description: "i16 min value".to_string(),
        type_name: "i16".to_string(),
        input_value: serde_json::json!(i16::MIN),
        expected_hex: bytes_to_hex(&bincode::serialize(&i16::MIN).unwrap()),
    });

    // i32
    vectors.push(PrimitiveVector {
        id: "i32_negative_50".to_string(),
        description: "i32 value -50".to_string(),
        type_name: "i32".to_string(),
        input_value: serde_json::json!(-50),
        expected_hex: bytes_to_hex(&bincode::serialize(&(-50i32)).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "i32_min".to_string(),
        description: "i32 min value".to_string(),
        type_name: "i32".to_string(),
        input_value: serde_json::json!(i32::MIN),
        expected_hex: bytes_to_hex(&bincode::serialize(&i32::MIN).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "i32_max".to_string(),
        description: "i32 max value".to_string(),
        type_name: "i32".to_string(),
        input_value: serde_json::json!(i32::MAX),
        expected_hex: bytes_to_hex(&bincode::serialize(&i32::MAX).unwrap()),
    });

    // i64
    vectors.push(PrimitiveVector {
        id: "i64_negative_1".to_string(),
        description: "i64 value -1".to_string(),
        type_name: "i64".to_string(),
        input_value: serde_json::json!("-1"),
        expected_hex: bytes_to_hex(&bincode::serialize(&(-1i64)).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "i64_min".to_string(),
        description: "i64 min value".to_string(),
        type_name: "i64".to_string(),
        input_value: serde_json::json!("-9223372036854775808"),
        expected_hex: bytes_to_hex(&bincode::serialize(&i64::MIN).unwrap()),
    });

    // bool
    vectors.push(PrimitiveVector {
        id: "bool_false".to_string(),
        description: "bool false".to_string(),
        type_name: "bool".to_string(),
        input_value: serde_json::json!(false),
        expected_hex: bytes_to_hex(&bincode::serialize(&false).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "bool_true".to_string(),
        description: "bool true".to_string(),
        type_name: "bool".to_string(),
        input_value: serde_json::json!(true),
        expected_hex: bytes_to_hex(&bincode::serialize(&true).unwrap()),
    });

    // f32
    vectors.push(PrimitiveVector {
        id: "f32_1_5".to_string(),
        description: "f32 value 1.5".to_string(),
        type_name: "f32".to_string(),
        input_value: serde_json::json!(1.5),
        expected_hex: bytes_to_hex(&bincode::serialize(&1.5f32).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "f32_zero".to_string(),
        description: "f32 value 0.0".to_string(),
        type_name: "f32".to_string(),
        input_value: serde_json::json!(0.0),
        expected_hex: bytes_to_hex(&bincode::serialize(&0.0f32).unwrap()),
    });

    // f64
    vectors.push(PrimitiveVector {
        id: "f64_1_5".to_string(),
        description: "f64 value 1.5".to_string(),
        type_name: "f64".to_string(),
        input_value: serde_json::json!(1.5),
        expected_hex: bytes_to_hex(&bincode::serialize(&1.5f64).unwrap()),
    });

    vectors.push(PrimitiveVector {
        id: "f64_pi".to_string(),
        description: "f64 value pi".to_string(),
        type_name: "f64".to_string(),
        input_value: serde_json::json!(std::f64::consts::PI),
        expected_hex: bytes_to_hex(&bincode::serialize(&std::f64::consts::PI).unwrap()),
    });

    vectors
}

#[allow(clippy::vec_init_then_push)]
fn generate_string_bytes_vectors() -> Vec<StringBytesVector> {
    let mut vectors = Vec::new();

    // Empty string
    vectors.push(StringBytesVector {
        id: "string_empty".to_string(),
        description: "Empty string".to_string(),
        type_name: "string".to_string(),
        input_value: "".to_string(),
        expected_hex: bytes_to_hex(&bincode::serialize(&"".to_string()).unwrap()),
    });

    // Simple ASCII
    vectors.push(StringBytesVector {
        id: "string_hello".to_string(),
        description: "String 'hello'".to_string(),
        type_name: "string".to_string(),
        input_value: "hello".to_string(),
        expected_hex: bytes_to_hex(&bincode::serialize(&"hello".to_string()).unwrap()),
    });

    // Longer string
    vectors.push(StringBytesVector {
        id: "string_hello_world".to_string(),
        description: "String 'Hello, World!'".to_string(),
        type_name: "string".to_string(),
        input_value: "Hello, World!".to_string(),
        expected_hex: bytes_to_hex(&bincode::serialize(&"Hello, World!".to_string()).unwrap()),
    });

    // Unicode
    vectors.push(StringBytesVector {
        id: "string_unicode".to_string(),
        description: "String with Unicode characters".to_string(),
        type_name: "string".to_string(),
        input_value: "Hello 世界".to_string(),
        expected_hex: bytes_to_hex(&bincode::serialize(&"Hello 世界".to_string()).unwrap()),
    });

    // Emoji
    vectors.push(StringBytesVector {
        id: "string_emoji".to_string(),
        description: "String with emoji".to_string(),
        type_name: "string".to_string(),
        input_value: "Hello 🌍🚀".to_string(),
        expected_hex: bytes_to_hex(&bincode::serialize(&"Hello 🌍🚀".to_string()).unwrap()),
    });

    vectors
}

#[allow(clippy::vec_init_then_push)]
fn generate_collection_vectors() -> Vec<CollectionVector> {
    let mut vectors = Vec::new();

    // Empty vec
    vectors.push(CollectionVector {
        id: "vec_u32_empty".to_string(),
        description: "Empty Vec<u32>".to_string(),
        type_name: "vec".to_string(),
        element_type: "u32".to_string(),
        input_value: serde_json::json!([]),
        expected_hex: bytes_to_hex(&bincode::serialize(&Vec::<u32>::new()).unwrap()),
    });

    // Vec<u32>
    vectors.push(CollectionVector {
        id: "vec_u32_123".to_string(),
        description: "Vec<u32> [1, 2, 3]".to_string(),
        type_name: "vec".to_string(),
        element_type: "u32".to_string(),
        input_value: serde_json::json!([1, 2, 3]),
        expected_hex: bytes_to_hex(&bincode::serialize(&vec![1u32, 2, 3]).unwrap()),
    });

    // Vec<u8>
    vectors.push(CollectionVector {
        id: "vec_u8_bytes".to_string(),
        description: "Vec<u8> [0xde, 0xad, 0xbe, 0xef]".to_string(),
        type_name: "vec".to_string(),
        element_type: "u8".to_string(),
        input_value: serde_json::json!([0xde, 0xad, 0xbe, 0xef]),
        expected_hex: bytes_to_hex(&bincode::serialize(&vec![0xdeu8, 0xad, 0xbe, 0xef]).unwrap()),
    });

    // Vec<u64> (as strings for JSON compatibility)
    vectors.push(CollectionVector {
        id: "vec_u64".to_string(),
        description: "Vec<u64> with large values".to_string(),
        type_name: "vec".to_string(),
        element_type: "u64".to_string(),
        input_value: serde_json::json!(["1000000000", "2000000000"]),
        expected_hex: bytes_to_hex(
            &bincode::serialize(&vec![1_000_000_000u64, 2_000_000_000u64]).unwrap(),
        ),
    });

    // Tuple (u8, u16, u32)
    vectors.push(CollectionVector {
        id: "tuple_u8_u16_u32".to_string(),
        description: "Tuple (u8, u16, u32) = (1, 2, 3)".to_string(),
        type_name: "tuple".to_string(),
        element_type: "u8,u16,u32".to_string(),
        input_value: serde_json::json!([1, 2, 3]),
        expected_hex: bytes_to_hex(&bincode::serialize(&(1u8, 2u16, 3u32)).unwrap()),
    });

    vectors
}

#[allow(clippy::vec_init_then_push)]
fn generate_option_vectors() -> Vec<OptionVector> {
    let mut vectors = Vec::new();

    // Option<u32> None
    vectors.push(OptionVector {
        id: "option_u32_none".to_string(),
        description: "Option<u32> None".to_string(),
        inner_type: "u32".to_string(),
        is_some: false,
        input_value: serde_json::Value::Null,
        expected_hex: bytes_to_hex(&bincode::serialize(&None::<u32>).unwrap()),
    });

    // Option<u32> Some(42)
    vectors.push(OptionVector {
        id: "option_u32_some_42".to_string(),
        description: "Option<u32> Some(42)".to_string(),
        inner_type: "u32".to_string(),
        is_some: true,
        input_value: serde_json::json!(42),
        expected_hex: bytes_to_hex(&bincode::serialize(&Some(42u32)).unwrap()),
    });

    // Option<u64> Some
    vectors.push(OptionVector {
        id: "option_u64_some".to_string(),
        description: "Option<u64> Some(1000000000)".to_string(),
        inner_type: "u64".to_string(),
        is_some: true,
        input_value: serde_json::json!("1000000000"),
        expected_hex: bytes_to_hex(&bincode::serialize(&Some(1_000_000_000u64)).unwrap()),
    });

    // Option<String> None
    vectors.push(OptionVector {
        id: "option_string_none".to_string(),
        description: "Option<String> None".to_string(),
        inner_type: "string".to_string(),
        is_some: false,
        input_value: serde_json::Value::Null,
        expected_hex: bytes_to_hex(&bincode::serialize(&None::<String>).unwrap()),
    });

    // Option<String> Some
    vectors.push(OptionVector {
        id: "option_string_some".to_string(),
        description: "Option<String> Some('test')".to_string(),
        inner_type: "string".to_string(),
        is_some: true,
        input_value: serde_json::json!("test"),
        expected_hex: bytes_to_hex(&bincode::serialize(&Some("test".to_string())).unwrap()),
    });

    // Nested Option<Option<u8>>
    vectors.push(OptionVector {
        id: "option_option_u8_some_some".to_string(),
        description: "Option<Option<u8>> Some(Some(5))".to_string(),
        inner_type: "option_u8".to_string(),
        is_some: true,
        input_value: serde_json::json!(5),
        expected_hex: bytes_to_hex(&bincode::serialize(&Some(Some(5u8))).unwrap()),
    });

    vectors.push(OptionVector {
        id: "option_option_u8_none".to_string(),
        description: "Option<Option<u8>> None".to_string(),
        inner_type: "option_u8".to_string(),
        is_some: false,
        input_value: serde_json::Value::Null,
        expected_hex: bytes_to_hex(&bincode::serialize(&None::<Option<u8>>).unwrap()),
    });

    vectors
}

fn generate_struct_vectors() -> Vec<StructVector> {
    let mut vectors = Vec::new();

    // Simple Point struct
    let point = Point { x: 100, y: -50 };
    vectors.push(StructVector {
        id: "struct_point".to_string(),
        description: "Point { x: 100, y: -50 }".to_string(),
        schema: vec![
            FieldDef {
                name: "x".to_string(),
                type_name: "i32".to_string(),
            },
            FieldDef {
                name: "y".to_string(),
                type_name: "i32".to_string(),
            },
        ],
        input_value: serde_json::json!({"x": 100, "y": -50}),
        expected_hex: bytes_to_hex(&bincode::serialize(&point).unwrap()),
    });

    // Point at origin
    let origin = Point { x: 0, y: 0 };
    vectors.push(StructVector {
        id: "struct_point_origin".to_string(),
        description: "Point { x: 0, y: 0 }".to_string(),
        schema: vec![
            FieldDef {
                name: "x".to_string(),
                type_name: "i32".to_string(),
            },
            FieldDef {
                name: "y".to_string(),
                type_name: "i32".to_string(),
            },
        ],
        input_value: serde_json::json!({"x": 0, "y": 0}),
        expected_hex: bytes_to_hex(&bincode::serialize(&origin).unwrap()),
    });

    // Nested Line struct
    let line = Line {
        start: Point { x: 0, y: 0 },
        end: Point { x: 10, y: 20 },
    };
    vectors.push(StructVector {
        id: "struct_line".to_string(),
        description: "Line { start: Point(0,0), end: Point(10,20) }".to_string(),
        schema: vec![
            FieldDef {
                name: "start".to_string(),
                type_name: "Point".to_string(),
            },
            FieldDef {
                name: "end".to_string(),
                type_name: "Point".to_string(),
            },
        ],
        input_value: serde_json::json!({
            "start": {"x": 0, "y": 0},
            "end": {"x": 10, "y": 20}
        }),
        expected_hex: bytes_to_hex(&bincode::serialize(&line).unwrap()),
    });

    // TransferData with memo
    let transfer_with_memo = TransferData {
        amount: 1_000_000_000,
        memo: Some("test transfer".to_string()),
    };
    vectors.push(StructVector {
        id: "struct_transfer_with_memo".to_string(),
        description: "TransferData { amount: 1B, memo: Some('test transfer') }".to_string(),
        schema: vec![
            FieldDef {
                name: "amount".to_string(),
                type_name: "u64".to_string(),
            },
            FieldDef {
                name: "memo".to_string(),
                type_name: "option_string".to_string(),
            },
        ],
        input_value: serde_json::json!({
            "amount": "1000000000",
            "memo": "test transfer"
        }),
        expected_hex: bytes_to_hex(&bincode::serialize(&transfer_with_memo).unwrap()),
    });

    // TransferData without memo
    let transfer_no_memo = TransferData {
        amount: 500_000_000,
        memo: None,
    };
    vectors.push(StructVector {
        id: "struct_transfer_no_memo".to_string(),
        description: "TransferData { amount: 500M, memo: None }".to_string(),
        schema: vec![
            FieldDef {
                name: "amount".to_string(),
                type_name: "u64".to_string(),
            },
            FieldDef {
                name: "memo".to_string(),
                type_name: "option_string".to_string(),
            },
        ],
        input_value: serde_json::json!({
            "amount": "500000000",
            "memo": null
        }),
        expected_hex: bytes_to_hex(&bincode::serialize(&transfer_no_memo).unwrap()),
    });

    vectors
}

fn generate_enum_vectors() -> Vec<EnumVector> {
    let mut vectors = Vec::new();

    let variants = vec![
        VariantDef {
            name: "Active".to_string(),
            type_name: None,
        },
        VariantDef {
            name: "Pending".to_string(),
            type_name: Some("u32".to_string()),
        },
        VariantDef {
            name: "Error".to_string(),
            type_name: Some("string".to_string()),
        },
    ];

    // Unit variant
    vectors.push(EnumVector {
        id: "enum_status_active".to_string(),
        description: "Status::Active (unit variant, index 0)".to_string(),
        variants: variants.clone(),
        input_variant: "Active".to_string(),
        input_value: serde_json::Value::Null,
        expected_hex: bytes_to_hex(&bincode::serialize(&Status::Active).unwrap()),
    });

    // Tuple variant
    vectors.push(EnumVector {
        id: "enum_status_pending".to_string(),
        description: "Status::Pending(42) (tuple variant, index 1)".to_string(),
        variants: variants.clone(),
        input_variant: "Pending".to_string(),
        input_value: serde_json::json!(42),
        expected_hex: bytes_to_hex(&bincode::serialize(&Status::Pending(42)).unwrap()),
    });

    // String variant
    vectors.push(EnumVector {
        id: "enum_status_error".to_string(),
        description: "Status::Error('fail') (string variant, index 2)".to_string(),
        variants: variants.clone(),
        input_variant: "Error".to_string(),
        input_value: serde_json::json!("fail"),
        expected_hex: bytes_to_hex(
            &bincode::serialize(&Status::Error("fail".to_string())).unwrap(),
        ),
    });

    // Simple unit-only enum
    let simple_variants = vec![
        VariantDef {
            name: "A".to_string(),
            type_name: None,
        },
        VariantDef {
            name: "B".to_string(),
            type_name: None,
        },
        VariantDef {
            name: "C".to_string(),
            type_name: None,
        },
    ];

    vectors.push(EnumVector {
        id: "enum_simple_a".to_string(),
        description: "SimpleEnum::A (index 0)".to_string(),
        variants: simple_variants.clone(),
        input_variant: "A".to_string(),
        input_value: serde_json::Value::Null,
        expected_hex: bytes_to_hex(&bincode::serialize(&SimpleEnum::A).unwrap()),
    });

    vectors.push(EnumVector {
        id: "enum_simple_c".to_string(),
        description: "SimpleEnum::C (index 2)".to_string(),
        variants: simple_variants,
        input_variant: "C".to_string(),
        input_value: serde_json::Value::Null,
        expected_hex: bytes_to_hex(&bincode::serialize(&SimpleEnum::C).unwrap()),
    });

    vectors
}

fn generate_fixed_array_vectors() -> Vec<FixedArrayVector> {
    let mut vectors = Vec::new();

    // 32-byte pubkey-like array (all zeros)
    let pubkey_zeros = [0u8; 32];
    vectors.push(FixedArrayVector {
        id: "fixed_32_zeros".to_string(),
        description: "32-byte array of zeros (like empty pubkey)".to_string(),
        length: 32,
        input_hex: bytes_to_hex(&pubkey_zeros),
        expected_hex: bytes_to_hex(&bincode::serialize(&pubkey_zeros).unwrap()),
    });

    // 32-byte pubkey-like array with pattern
    let mut pubkey_pattern = [0u8; 32];
    pubkey_pattern[0] = 0x11;
    pubkey_pattern[31] = 0xff;
    vectors.push(FixedArrayVector {
        id: "fixed_32_pattern".to_string(),
        description: "32-byte array with pattern (first=0x11, last=0xff)".to_string(),
        length: 32,
        input_hex: bytes_to_hex(&pubkey_pattern),
        expected_hex: bytes_to_hex(&bincode::serialize(&pubkey_pattern).unwrap()),
    });

    // 8-byte discriminator
    let discriminator: [u8; 8] = [0xaf, 0xaf, 0x6d, 0x1f, 0x0d, 0x98, 0x9b, 0xed];
    vectors.push(FixedArrayVector {
        id: "fixed_8_discriminator".to_string(),
        description: "8-byte discriminator".to_string(),
        length: 8,
        input_hex: bytes_to_hex(&discriminator),
        expected_hex: bytes_to_hex(&bincode::serialize(&discriminator).unwrap()),
    });

    vectors
}

fn generate_instruction_vectors() -> Vec<InstructionVector> {
    let mut vectors = Vec::new();

    // Transfer instruction without memo
    #[derive(Serialize)]
    struct TransferInstruction {
        discriminator: [u8; 8],
        amount: u64,
        memo: Option<String>,
    }

    let discriminator: [u8; 8] = [0xaf, 0xaf, 0x6d, 0x1f, 0x0d, 0x98, 0x9b, 0xed];

    let transfer_no_memo = TransferInstruction {
        discriminator,
        amount: 1_000_000_000,
        memo: None,
    };

    vectors.push(InstructionVector {
        id: "instruction_transfer_no_memo".to_string(),
        description: "Transfer instruction: 1 SOL, no memo".to_string(),
        schema: vec![
            FieldDef {
                name: "discriminator".to_string(),
                type_name: "fixed_array_8".to_string(),
            },
            FieldDef {
                name: "amount".to_string(),
                type_name: "u64".to_string(),
            },
            FieldDef {
                name: "memo".to_string(),
                type_name: "option_string".to_string(),
            },
        ],
        input_value: serde_json::json!({
            "discriminator": bytes_to_hex(&discriminator),
            "amount": "1000000000",
            "memo": null
        }),
        expected_hex: bytes_to_hex(&bincode::serialize(&transfer_no_memo).unwrap()),
    });

    // Transfer instruction with memo
    let transfer_with_memo = TransferInstruction {
        discriminator,
        amount: 500_000_000,
        memo: Some("test".to_string()),
    };

    vectors.push(InstructionVector {
        id: "instruction_transfer_with_memo".to_string(),
        description: "Transfer instruction: 0.5 SOL, with memo 'test'".to_string(),
        schema: vec![
            FieldDef {
                name: "discriminator".to_string(),
                type_name: "fixed_array_8".to_string(),
            },
            FieldDef {
                name: "amount".to_string(),
                type_name: "u64".to_string(),
            },
            FieldDef {
                name: "memo".to_string(),
                type_name: "option_string".to_string(),
            },
        ],
        input_value: serde_json::json!({
            "discriminator": bytes_to_hex(&discriminator),
            "amount": "500000000",
            "memo": "test"
        }),
        expected_hex: bytes_to_hex(&bincode::serialize(&transfer_with_memo).unwrap()),
    });

    // Complex instruction with multiple fields
    #[derive(Serialize)]
    struct ComplexInstruction {
        instruction_type: u8,
        source: [u8; 32],
        destination: [u8; 32],
        amount: u64,
        fee: u64,
    }

    let mut source = [0u8; 32];
    source[0] = 0xaa;
    let mut dest = [0u8; 32];
    dest[0] = 0xbb;

    let complex = ComplexInstruction {
        instruction_type: 2,
        source,
        destination: dest,
        amount: 1_000_000_000,
        fee: 5000,
    };

    vectors.push(InstructionVector {
        id: "instruction_complex".to_string(),
        description: "Complex instruction with pubkeys and amounts".to_string(),
        schema: vec![
            FieldDef {
                name: "instruction_type".to_string(),
                type_name: "u8".to_string(),
            },
            FieldDef {
                name: "source".to_string(),
                type_name: "pubkey".to_string(),
            },
            FieldDef {
                name: "destination".to_string(),
                type_name: "pubkey".to_string(),
            },
            FieldDef {
                name: "amount".to_string(),
                type_name: "u64".to_string(),
            },
            FieldDef {
                name: "fee".to_string(),
                type_name: "u64".to_string(),
            },
        ],
        input_value: serde_json::json!({
            "instruction_type": 2,
            "source": bytes_to_hex(&source),
            "destination": bytes_to_hex(&dest),
            "amount": "1000000000",
            "fee": "5000"
        }),
        expected_hex: bytes_to_hex(&bincode::serialize(&complex).unwrap()),
    });

    vectors
}

// ========== Public API ==========

pub fn generate() {
    eprintln!("Generating cross-platform bincode test vectors");

    let test_vectors = TestVectors {
        version: "1.0.0".to_string(),
        vectors: Vectors {
            primitives: generate_primitive_vectors(),
            strings_and_bytes: generate_string_bytes_vectors(),
            collections: generate_collection_vectors(),
            options: generate_option_vectors(),
            structs: generate_struct_vectors(),
            enums: generate_enum_vectors(),
            fixed_arrays: generate_fixed_array_vectors(),
            instruction_patterns: generate_instruction_vectors(),
        },
    };

    // Serialize to JSON with pretty printing
    let json =
        serde_json::to_string_pretty(&test_vectors).expect("Failed to serialize test vectors");

    // Write to file
    let manifest_dir = env!("CARGO_MANIFEST_DIR");
    let output_path = format!("{manifest_dir}/test-vectors/bincode-vectors.json");
    fs::write(&output_path, json).expect("Failed to write test vectors");

    eprintln!("Bincode test vectors generated successfully");
    eprintln!("Output: {output_path}");
    eprintln!(
        "Generated {} primitive vectors",
        test_vectors.vectors.primitives.len()
    );
    eprintln!(
        "Generated {} string/bytes vectors",
        test_vectors.vectors.strings_and_bytes.len()
    );
    eprintln!(
        "Generated {} collection vectors",
        test_vectors.vectors.collections.len()
    );
    eprintln!(
        "Generated {} option vectors",
        test_vectors.vectors.options.len()
    );
    eprintln!(
        "Generated {} struct vectors",
        test_vectors.vectors.structs.len()
    );
    eprintln!(
        "Generated {} enum vectors",
        test_vectors.vectors.enums.len()
    );
    eprintln!(
        "Generated {} fixed array vectors",
        test_vectors.vectors.fixed_arrays.len()
    );
    eprintln!(
        "Generated {} instruction vectors",
        test_vectors.vectors.instruction_patterns.len()
    );
}
