use super::artifact::build_artifact;
use crate::model::{ArtifactGroup, GeneratedArtifact, TransportKind, ValueType};
use crate::planner::{
    normalize_type_name, to_upper_snake_case, AreaKind, ContractPlan, ItemPlan, MethodPlan,
    MethodWireKind, PlannedValue,
};
use std::collections::BTreeMap;

pub(super) fn render_rust_artifact(
    plan: &ContractPlan,
    transport: &TransportKind,
) -> GeneratedArtifact {
    build_artifact(
        format!(
            "Docs/generated/modbus/rust/okm_modbus_{}_tokio_client.rs",
            transport.file_segment()
        ),
        None,
        ArtifactGroup::RustTokioModbus,
        transport.clone(),
        render_rust_client(plan, transport),
    )
}

fn render_rust_client(plan: &ContractPlan, transport: &TransportKind) -> String {
    [
        format!("// 自动生成：{} Rust 设备合同实现", transport.as_str()),
        render_rust_prelude(transport),
        render_rust_error_type(),
        render_rust_manifest_constants(plan),
        render_rust_common_types(plan),
        render_rust_transport_trait(),
        render_rust_transport_impl(transport),
        render_rust_service_traits(plan),
        render_rust_service_impls(plan),
        render_rust_helpers(),
    ]
    .join("\n\n")
}

fn render_rust_prelude(transport: &TransportKind) -> String {
    match transport {
        TransportKind::Rtu => [
            "use serialport::{DataBits, Parity, StopBits};",
            "use std::time::Duration;",
            "use tokio_modbus::client::sync::rtu;",
            "use tokio_modbus::prelude::{Slave, SyncReader, SyncWriter};",
            "",
            "#[derive(Debug, Clone)]",
            "pub struct OkmModbusRtuConfig {",
            "    pub port_name: String,",
            "    pub baud_rate: u32,",
            "    pub data_bits: u8,",
            "    pub stop_bits: u8,",
            "    pub parity: String,",
            "    pub timeout: Option<Duration>,",
            "    pub slave: u8,",
            "}",
            "",
            "pub fn connect_okm_modbus_rtu(config: &OkmModbusRtuConfig) -> std::io::Result<tokio_modbus::client::sync::Context> {",
            "    let data_bits = match config.data_bits {",
            "        5 => DataBits::Five,",
            "        6 => DataBits::Six,",
            "        7 => DataBits::Seven,",
            "        _ => DataBits::Eight,",
            "    };",
            "    let stop_bits = match config.stop_bits {",
            "        2 => StopBits::Two,",
            "        _ => StopBits::One,",
            "    };",
            "    let parity = match config.parity.trim().to_uppercase().as_str() {",
            "        \"ODD\" => Parity::Odd,",
            "        \"EVEN\" => Parity::Even,",
            "        _ => Parity::None,",
            "    };",
            "    let builder = serialport::new(config.port_name.trim(), config.baud_rate)",
            "        .data_bits(data_bits)",
            "        .stop_bits(stop_bits)",
            "        .parity(parity)",
            "        .timeout(config.timeout.unwrap_or_else(|| Duration::from_millis(300)));",
            "    let mut context = rtu::connect_slave(&builder, Slave(config.slave))?;",
            "    context.set_timeout(config.timeout);",
            "    Ok(context)",
            "}",
        ]
        .join("\n"),
        TransportKind::Tcp => [
            "use std::net::{IpAddr, SocketAddr};",
            "use std::time::Duration;",
            "use tokio_modbus::client::sync::tcp;",
            "use tokio_modbus::prelude::{Slave, SyncReader, SyncWriter};",
            "",
            "#[derive(Debug, Clone)]",
            "pub struct OkmModbusTcpConfig {",
            "    pub host: String,",
            "    pub port: u16,",
            "    pub timeout: Option<Duration>,",
            "    pub slave: u8,",
            "}",
            "",
            "pub fn connect_okm_modbus_tcp(config: &OkmModbusTcpConfig) -> std::io::Result<tokio_modbus::client::sync::Context> {",
            "    let ip = config.host.parse::<IpAddr>().map_err(|error| std::io::Error::new(std::io::ErrorKind::InvalidInput, error.to_string()))?;",
            "    let socket = SocketAddr::new(ip, config.port);",
            "    tcp::connect_slave_with_timeout(socket, Slave(config.slave), config.timeout)",
            "}",
        ]
        .join("\n"),
    }
}

fn render_rust_error_type() -> String {
    [
        "#[derive(Debug, Clone, PartialEq, Eq)]",
        "pub struct DeviceApiError {",
        "    pub message: String,",
        "}",
        "",
        "impl DeviceApiError {",
        "    pub fn new(message: impl Into<String>) -> Self {",
        "        Self {",
        "            message: message.into(),",
        "        }",
        "    }",
        "}",
        "",
        "impl std::fmt::Display for DeviceApiError {",
        "    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {",
        "        formatter.write_str(&self.message)",
        "    }",
        "}",
        "",
        "impl std::error::Error for DeviceApiError {}",
    ]
    .join("\n")
}

fn render_rust_manifest_constants(plan: &ContractPlan) -> String {
    let mut lines = Vec::new();
    for method in &plan.methods {
        let base = rust_method_manifest_prefix(method);
        lines.push(format!(
            "pub const {base}_START_ADDRESS: u16 = {};",
            method.start_address
        ));
        lines.push(format!(
            "pub const {base}_QUANTITY: u16 = {};",
            method.quantity
        ));
        lines.push(String::new());
    }
    lines.join("\n")
}

fn render_rust_common_types(plan: &ContractPlan) -> String {
    let mut lines = vec![
        "#[derive(Debug, Clone, PartialEq, Eq)]".to_string(),
        "pub struct OkmModbusString32 {".to_string(),
        "    pub value: String,".to_string(),
        "}".to_string(),
        "".to_string(),
        "#[derive(Debug, Clone, PartialEq, Eq)]".to_string(),
        "pub struct OkmModbusBytes32 {".to_string(),
        "    pub data: Vec<u8>,".to_string(),
        "}".to_string(),
        "".to_string(),
    ];
    let mut rendered_types = BTreeMap::new();
    for method in &plan.methods {
        if let PlannedValue::Dto { type_name, items } = &method.planned_value {
            rendered_types.entry(type_name.clone()).or_insert_with(|| {
                let mut content = vec![
                    "#[derive(Debug, Clone, PartialEq, Eq)]".to_string(),
                    format!("pub struct {} {{", normalize_type_name(type_name)),
                ];
                for item in items {
                    content.push(format!(
                        "    pub {}: {},",
                        item.name,
                        rust_value_type(&item.value_type)
                    ));
                }
                content.push("}".to_string());
                content.join("\n")
            });
        }
    }
    lines.extend(rendered_types.into_values());
    lines.join("\n")
}

fn render_rust_transport_trait() -> String {
    [
        "pub trait RegisterTransport: Send + Sync {",
        "    fn read_coils(&self, start: u16, quantity: u16) -> Result<Vec<bool>, DeviceApiError>;",
        "    fn read_discrete_inputs(&self, start: u16, quantity: u16) -> Result<Vec<bool>, DeviceApiError>;",
        "    fn read_holding_registers(&self, start: u16, quantity: u16) -> Result<Vec<u16>, DeviceApiError>;",
        "    fn read_input_registers(&self, start: u16, quantity: u16) -> Result<Vec<u16>, DeviceApiError>;",
        "    fn write_coils(&self, start: u16, values: &[bool]) -> Result<(), DeviceApiError>;",
        "    fn write_holding_registers(&self, start: u16, values: &[u16]) -> Result<(), DeviceApiError>;",
        "}",
    ]
    .join("\n")
}

fn render_rust_transport_impl(transport: &TransportKind) -> String {
    let (transport_name, config_name, connect_function) = match transport {
        TransportKind::Rtu => (
            "ModbusRtuTransport",
            "OkmModbusRtuConfig",
            "connect_okm_modbus_rtu",
        ),
        TransportKind::Tcp => (
            "ModbusTcpTransport",
            "OkmModbusTcpConfig",
            "connect_okm_modbus_tcp",
        ),
    };
    [
        "#[derive(Debug, Clone)]".to_string(),
        format!("pub struct {transport_name} {{"),
        format!("    pub config: {config_name},"),
        "}".to_string(),
        "".to_string(),
        format!("impl {transport_name} {{"),
        format!("    pub fn new(config: {config_name}) -> Self {{"),
        "        Self {".to_string(),
        "            config,".to_string(),
        "        }".to_string(),
        "    }".to_string(),
        "".to_string(),
        "    fn with_context<T>(".to_string(),
        "        &self,".to_string(),
        "        task: impl FnOnce(&mut tokio_modbus::client::sync::Context) -> Result<T, DeviceApiError>,"
            .to_string(),
        "    ) -> Result<T, DeviceApiError> {".to_string(),
        format!("        let mut context = {connect_function}(&self.config)")
            .to_string(),
        "            .map_err(|error| DeviceApiError::new(error.to_string()))?;".to_string(),
        "        task(&mut context)".to_string(),
        "    }".to_string(),
        "}".to_string(),
        "".to_string(),
        format!("impl RegisterTransport for {transport_name} {{"),
        "    fn read_coils(&self, start: u16, quantity: u16) -> Result<Vec<bool>, DeviceApiError> {"
            .to_string(),
        "        self.with_context(|context| {".to_string(),
        "            context".to_string(),
        "                .read_coils(start, quantity)".to_string(),
        "                .map_err(|error| DeviceApiError::new(error.to_string()))?".to_string(),
        "                .map_err(|error| DeviceApiError::new(format!(\"Modbus 异常: {error:?}\")))"
            .to_string(),
        "        })".to_string(),
        "    }".to_string(),
        "".to_string(),
        "    fn read_discrete_inputs(&self, start: u16, quantity: u16) -> Result<Vec<bool>, DeviceApiError> {"
            .to_string(),
        "        self.with_context(|context| {".to_string(),
        "            context".to_string(),
        "                .read_discrete_inputs(start, quantity)".to_string(),
        "                .map_err(|error| DeviceApiError::new(error.to_string()))?".to_string(),
        "                .map_err(|error| DeviceApiError::new(format!(\"Modbus 异常: {error:?}\")))"
            .to_string(),
        "        })".to_string(),
        "    }".to_string(),
        "".to_string(),
        "    fn read_holding_registers(&self, start: u16, quantity: u16) -> Result<Vec<u16>, DeviceApiError> {"
            .to_string(),
        "        self.with_context(|context| {".to_string(),
        "            context".to_string(),
        "                .read_holding_registers(start, quantity)".to_string(),
        "                .map_err(|error| DeviceApiError::new(error.to_string()))?".to_string(),
        "                .map_err(|error| DeviceApiError::new(format!(\"Modbus 异常: {error:?}\")))"
            .to_string(),
        "        })".to_string(),
        "    }".to_string(),
        "".to_string(),
        "    fn read_input_registers(&self, start: u16, quantity: u16) -> Result<Vec<u16>, DeviceApiError> {"
            .to_string(),
        "        self.with_context(|context| {".to_string(),
        "            context".to_string(),
        "                .read_input_registers(start, quantity)".to_string(),
        "                .map_err(|error| DeviceApiError::new(error.to_string()))?".to_string(),
        "                .map_err(|error| DeviceApiError::new(format!(\"Modbus 异常: {error:?}\")))"
            .to_string(),
        "        })".to_string(),
        "    }".to_string(),
        "".to_string(),
        "    fn write_coils(&self, start: u16, values: &[bool]) -> Result<(), DeviceApiError> {"
            .to_string(),
        "        self.with_context(|context| match values {".to_string(),
        "            [] => Err(DeviceApiError::new(\"至少需要一个线圈值\")),".to_string(),
        "            [value] => {".to_string(),
        "                context".to_string(),
        "                    .write_single_coil(start, *value)".to_string(),
        "                    .map_err(|error| DeviceApiError::new(error.to_string()))?"
            .to_string(),
        "                    .map_err(|error| DeviceApiError::new(format!(\"Modbus 异常: {error:?}\")))?;"
            .to_string(),
        "                Ok(())".to_string(),
        "            }".to_string(),
        "            _ => {".to_string(),
        "                context".to_string(),
        "                    .write_multiple_coils(start, values)".to_string(),
        "                    .map_err(|error| DeviceApiError::new(error.to_string()))?"
            .to_string(),
        "                    .map_err(|error| DeviceApiError::new(format!(\"Modbus 异常: {error:?}\")))?;"
            .to_string(),
        "                Ok(())".to_string(),
        "            }".to_string(),
        "        })".to_string(),
        "    }".to_string(),
        "".to_string(),
        "    fn write_holding_registers(&self, start: u16, values: &[u16]) -> Result<(), DeviceApiError> {"
            .to_string(),
        "        self.with_context(|context| match values {".to_string(),
        "            [] => Err(DeviceApiError::new(\"至少需要一个保持寄存器值\")),".to_string(),
        "            [value] => {".to_string(),
        "                context".to_string(),
        "                    .write_single_register(start, *value)".to_string(),
        "                    .map_err(|error| DeviceApiError::new(error.to_string()))?"
            .to_string(),
        "                    .map_err(|error| DeviceApiError::new(format!(\"Modbus 异常: {error:?}\")))?;"
            .to_string(),
        "                Ok(())".to_string(),
        "            }".to_string(),
        "            _ => {".to_string(),
        "                context".to_string(),
        "                    .write_multiple_registers(start, values)".to_string(),
        "                    .map_err(|error| DeviceApiError::new(error.to_string()))?"
            .to_string(),
        "                    .map_err(|error| DeviceApiError::new(format!(\"Modbus 异常: {error:?}\")))?;"
            .to_string(),
        "                Ok(())".to_string(),
        "            }".to_string(),
        "        })".to_string(),
        "    }".to_string(),
        "}".to_string(),
    ]
    .join("\n")
}

fn render_rust_service_traits(plan: &ContractPlan) -> String {
    let mut lines = Vec::new();
    for service in &plan.services {
        let methods = service_methods(plan, service);
        lines.push(render_rust_service_trait(service, &methods));
    }
    lines.join("\n\n")
}

fn render_rust_service_trait(
    service: &crate::model::ContractService,
    methods: &[&MethodPlan],
) -> String {
    let trait_name = normalize_type_name(&service.interface_name);
    let mut lines = vec![format!("pub trait {trait_name}: Send + Sync {{")];
    for method in methods {
        lines.push(render_rust_trait_method_signature(method));
    }
    lines.push("}".to_string());
    lines.join("\n")
}

fn render_rust_service_impls(plan: &ContractPlan) -> String {
    let mut lines = Vec::new();
    for service in &plan.services {
        let methods = service_methods(plan, service);
        lines.push(render_rust_service_impl(service, &methods));
    }
    lines.join("\n\n")
}

fn render_rust_service_impl(
    service: &crate::model::ContractService,
    methods: &[&MethodPlan],
) -> String {
    let trait_name = normalize_type_name(&service.interface_name);
    let impl_name = format!("Modbus{trait_name}");
    let mut lines = vec![
        format!("pub struct {impl_name}<T> {{"),
        "    transport: T,".to_string(),
        "}".to_string(),
        "".to_string(),
        format!("impl<T> {impl_name}<T> {{"),
        "    pub fn new(transport: T) -> Self {".to_string(),
        "        Self {".to_string(),
        "            transport,".to_string(),
        "        }".to_string(),
        "    }".to_string(),
        "}".to_string(),
        "".to_string(),
        format!("impl<T> {trait_name} for {impl_name}<T>"),
        "where".to_string(),
        "    T: RegisterTransport,".to_string(),
        "{".to_string(),
    ];
    for method in methods {
        lines.push(render_rust_impl_method(method));
    }
    lines.push("}".to_string());
    lines.join("\n")
}

fn service_methods<'a>(
    plan: &'a ContractPlan,
    service: &crate::model::ContractService,
) -> Vec<&'a MethodPlan> {
    let interface_name = normalize_type_name(&service.interface_name);
    plan.methods
        .iter()
        .filter(|method| method.interface_name == interface_name)
        .collect::<Vec<_>>()
}

fn render_rust_trait_method_signature(method: &MethodPlan) -> String {
    let parameter_list = rust_method_parameter_list(method);
    let return_type = rust_method_return_type(method);
    if parameter_list.is_empty() {
        format!(
            "    fn {}(&self) -> Result<{}, DeviceApiError>;",
            method.rust_method_name, return_type
        )
    } else {
        format!(
            "    fn {}(&self, {}) -> Result<{}, DeviceApiError>;",
            method.rust_method_name, parameter_list, return_type
        )
    }
}

fn render_rust_impl_method(method: &MethodPlan) -> String {
    let parameter_list = rust_method_parameter_list(method);
    let return_type = rust_method_return_type(method);
    let mut lines = Vec::new();
    if parameter_list.is_empty() {
        lines.push(format!(
            "    fn {}(&self) -> Result<{}, DeviceApiError> {{",
            method.rust_method_name, return_type
        ));
    } else {
        lines.push(format!(
            "    fn {}(&self, {}) -> Result<{}, DeviceApiError> {{",
            method.rust_method_name, parameter_list, return_type
        ));
    }
    match &method.planned_value {
        PlannedValue::Parameters { .. } => lines.push(render_rust_write_body(method)),
        PlannedValue::Dto { .. } | PlannedValue::Scalar { .. } => {
            lines.push(render_rust_read_body(method))
        }
    }
    lines.push("    }".to_string());
    lines.join("\n")
}

fn render_rust_read_body(method: &MethodPlan) -> String {
    let base = rust_method_manifest_prefix(method);
    let transport_method = rust_transport_read_method(&method.area_kind);
    match &method.planned_value {
        PlannedValue::Dto { type_name, items } => {
            let return_type = normalize_type_name(type_name);
            match method.wire_kind {
                MethodWireKind::Bit => {
                    let mut lines = vec![format!(
                        "        let values = self.transport.{transport_method}({base}_START_ADDRESS, {base}_QUANTITY)?;"
                    )];
                    lines.push(format!("        Ok({return_type} {{"));
                    for item in items {
                        lines.push(format!("            {}: values[{}],", item.name, item.offset));
                    }
                    lines.push("        })".to_string());
                    lines.join("\n")
                }
                MethodWireKind::Register => {
                    let mut lines = vec![format!(
                        "        let registers = self.transport.{transport_method}({base}_START_ADDRESS, {base}_QUANTITY)?;"
                    )];
                    lines.push(format!("        Ok({return_type} {{"));
                    for item in items {
                        lines.push(format!(
                            "            {}: {},",
                            item.name,
                            rust_decode_expression(item, "registers")
                        ));
                    }
                    lines.push("        })".to_string());
                    lines.join("\n")
                }
            }
        }
        PlannedValue::Scalar { item } => match method.wire_kind {
            MethodWireKind::Bit => [
                format!(
                    "        let values = self.transport.{transport_method}({base}_START_ADDRESS, {base}_QUANTITY)?;"
                ),
                "        Ok(values[0])".to_string(),
            ]
            .join("\n"),
            MethodWireKind::Register => [
                format!(
                    "        let registers = self.transport.{transport_method}({base}_START_ADDRESS, {base}_QUANTITY)?;"
                ),
                format!("        Ok({})", rust_decode_expression(item, "registers")),
            ]
            .join("\n"),
        },
        PlannedValue::Parameters { .. } => String::new(),
    }
}

fn render_rust_write_body(method: &MethodPlan) -> String {
    let PlannedValue::Parameters { items } = &method.planned_value else {
        return String::new();
    };
    let base = rust_method_manifest_prefix(method);
    let transport_method = rust_transport_write_method(&method.area_kind);
    match method.wire_kind {
        MethodWireKind::Bit => {
            let values = items
                .iter()
                .map(|item| item.name.clone())
                .collect::<Vec<_>>()
                .join(", ");
            [
                format!("        let values = vec![{values}];"),
                format!(
                    "        self.transport.{transport_method}({base}_START_ADDRESS, &values)?;"
                ),
                "        Ok(())".to_string(),
            ]
            .join("\n")
        }
        MethodWireKind::Register => {
            let mut lines = vec!["        let mut registers = Vec::new();".to_string()];
            for item in items {
                lines.push(format!("        {}", rust_register_push(item)));
            }
            lines.push(format!(
                "        self.transport.{transport_method}({base}_START_ADDRESS, &registers)?;"
            ));
            lines.push("        Ok(())".to_string());
            lines.join("\n")
        }
    }
}

fn rust_method_manifest_prefix(method: &MethodPlan) -> String {
    format!(
        "OKM_MODBUS_{}_{}",
        to_upper_snake_case(&method.interface_name),
        to_upper_snake_case(&method.method_name)
    )
}

fn rust_method_return_type(method: &MethodPlan) -> String {
    match &method.planned_value {
        PlannedValue::Dto { type_name, .. } => normalize_type_name(type_name),
        PlannedValue::Scalar { item } => rust_value_type(&item.value_type).to_string(),
        PlannedValue::Parameters { .. } => "()".to_string(),
    }
}

fn rust_method_parameter_list(method: &MethodPlan) -> String {
    match &method.planned_value {
        PlannedValue::Parameters { items } => items
            .iter()
            .map(|item| format!("{}: {}", item.name, rust_argument_type(&item.value_type)))
            .collect::<Vec<_>>()
            .join(", "),
        PlannedValue::Dto { .. } | PlannedValue::Scalar { .. } => String::new(),
    }
}

fn rust_transport_read_method(area_kind: &AreaKind) -> &'static str {
    match area_kind {
        AreaKind::Coil => "read_coils",
        AreaKind::DiscreteInput => "read_discrete_inputs",
        AreaKind::HoldingRegister => "read_holding_registers",
        AreaKind::InputRegister => "read_input_registers",
    }
}

fn rust_transport_write_method(area_kind: &AreaKind) -> &'static str {
    match area_kind {
        AreaKind::Coil => "write_coils",
        AreaKind::HoldingRegister => "write_holding_registers",
        AreaKind::DiscreteInput | AreaKind::InputRegister => {
            unreachable!("读区域不能生成写调用")
        }
    }
}

fn render_rust_helpers() -> String {
    [
        "fn decode_i32(registers: &[u16], offset: usize) -> i32 {",
        "    (((registers[offset] as u32) << 16) | registers[offset + 1] as u32) as i32",
        "}",
        "",
        "fn encode_i32(value: i32) -> [u16; 2] {",
        "    let raw = value as u32;",
        "    [((raw >> 16) & 0xFFFF) as u16, (raw & 0xFFFF) as u16]",
        "}",
        "",
        "fn decode_string32(registers: &[u16], offset: usize) -> OkmModbusString32 {",
        "    let length = registers[offset].min(32) as usize;",
        "    let mut bytes = Vec::with_capacity(length);",
        "    for index in 0..length {",
        "        let register = registers[offset + 1 + (index / 2)];",
        "        let value = if index % 2 == 0 { (register >> 8) as u8 } else { (register & 0x00FF) as u8 };",
        "        bytes.push(value);",
        "    }",
        "    OkmModbusString32 { value: String::from_utf8_lossy(&bytes).to_string() }",
        "}",
        "",
        "fn decode_bytes32(registers: &[u16], offset: usize) -> OkmModbusBytes32 {",
        "    let length = registers[offset].min(32) as usize;",
        "    let mut bytes = Vec::with_capacity(length);",
        "    for index in 0..length {",
        "        let register = registers[offset + 1 + (index / 2)];",
        "        let value = if index % 2 == 0 { (register >> 8) as u8 } else { (register & 0x00FF) as u8 };",
        "        bytes.push(value);",
        "    }",
        "    OkmModbusBytes32 { data: bytes }",
        "}",
        "",
        "fn encode_string32(value: &OkmModbusString32) -> Vec<u16> {",
        "    let bytes = value.value.as_bytes();",
        "    let length = bytes.len().min(32);",
        "    let mut registers = vec![0_u16; 17];",
        "    registers[0] = length as u16;",
        "    for index in (0..length).step_by(2) {",
        "        let high = bytes[index] as u16;",
        "        let low = if index + 1 < length { bytes[index + 1] as u16 } else { 0 };",
        "        registers[1 + (index / 2)] = (high << 8) | low;",
        "    }",
        "    registers",
        "}",
        "",
        "fn encode_bytes32(value: &OkmModbusBytes32) -> Vec<u16> {",
        "    let length = value.data.len().min(32);",
        "    let mut registers = vec![0_u16; 17];",
        "    registers[0] = length as u16;",
        "    for index in (0..length).step_by(2) {",
        "        let high = value.data[index] as u16;",
        "        let low = if index + 1 < length { value.data[index + 1] as u16 } else { 0 };",
        "        registers[1 + (index / 2)] = (high << 8) | low;",
        "    }",
        "    registers",
        "}",
        "",
    ]
    .join("\n")
}

fn rust_register_push(item: &ItemPlan) -> String {
    match item.value_type {
        ValueType::Boolean => format!("    registers.push(if {} {{ 1 }} else {{ 0 }});", item.name),
        ValueType::Int => format!(
            "    registers.extend_from_slice(&encode_i32({}));",
            item.name
        ),
        ValueType::String => format!(
            "    registers.extend_from_slice(&encode_string32({}));",
            item.name
        ),
        ValueType::Bytes => format!(
            "    registers.extend_from_slice(&encode_bytes32({}));",
            item.name
        ),
    }
}

fn rust_decode_expression(item: &ItemPlan, buffer_name: &str) -> String {
    match item.value_type {
        ValueType::Boolean => format!("{buffer_name}[{}] != 0", item.offset),
        ValueType::Int => format!("decode_i32(&{buffer_name}, {})", item.offset),
        ValueType::String => format!("decode_string32(&{buffer_name}, {})", item.offset),
        ValueType::Bytes => format!("decode_bytes32(&{buffer_name}, {})", item.offset),
    }
}

fn rust_value_type(value_type: &ValueType) -> &'static str {
    match value_type {
        ValueType::Boolean => "bool",
        ValueType::Int => "i32",
        ValueType::String => "OkmModbusString32",
        ValueType::Bytes => "OkmModbusBytes32",
    }
}

fn rust_argument_type(value_type: &ValueType) -> &'static str {
    match value_type {
        ValueType::Boolean => "bool",
        ValueType::Int => "i32",
        ValueType::String => "&OkmModbusString32",
        ValueType::Bytes => "&OkmModbusBytes32",
    }
}
