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

pub(super) fn render_common_c_artifacts(
    plan: &ContractPlan,
    transport: &TransportKind,
) -> Vec<GeneratedArtifact> {
    let mut artifacts = vec![
        build_artifact(
            "Core/Inc/generated/modbus/okm_modbus_common.h",
            None,
            ArtifactGroup::CServiceContract,
            transport.clone(),
            render_c_common_header(),
        ),
        build_artifact(
            "Core/Inc/generated/modbus/okm_modbus_manifest.h",
            None,
            ArtifactGroup::CServiceContract,
            transport.clone(),
            render_c_manifest_header(plan),
        ),
        build_artifact(
            "Core/Inc/generated/modbus/okm_modbus_dispatch.h",
            None,
            ArtifactGroup::CTransportContract,
            transport.clone(),
            render_c_dispatch_header(),
        ),
        build_artifact(
            "Core/Src/generated/modbus/okm_modbus_dispatch.c",
            None,
            ArtifactGroup::CTransportContract,
            transport.clone(),
            render_c_dispatch_source(plan),
        ),
    ];

    for service in &plan.services {
        artifacts.push(build_artifact(
            format!(
                "Core/Inc/generated/modbus/{}_service.h",
                to_snake_case(&service.interface_name)
            ),
            Some(normalize_type_name(&service.interface_name)),
            ArtifactGroup::CServiceContract,
            transport.clone(),
            render_c_service_header(plan, service),
        ));
    }
    artifacts
}

pub(super) fn render_transport_c_artifacts(
    plan: &ContractPlan,
    transport: &TransportKind,
) -> Vec<GeneratedArtifact> {
    let segment = transport.file_segment();
    let transport_label = transport.as_str();
    vec![
        build_artifact(
            format!("Core/Inc/generated/modbus/{segment}/okm_modbus_{segment}.h"),
            None,
            ArtifactGroup::CTransportContract,
            transport.clone(),
            render_c_transport_header(transport_label, segment),
        ),
        build_artifact(
            format!("Core/Src/generated/modbus/{segment}/okm_modbus_{segment}.c"),
            None,
            ArtifactGroup::CTransportContract,
            transport.clone(),
            render_c_transport_source(plan, transport),
        ),
    ]
}

fn render_c_common_header() -> String {
    vec![
        "/* 自动生成：通用 Modbus 合同类型 */".to_string(),
        "#ifndef OKM_MODBUS_COMMON_H".to_string(),
        "#define OKM_MODBUS_COMMON_H".to_string(),
        "".to_string(),
        "#include <stdbool.h>".to_string(),
        "#include <stddef.h>".to_string(),
        "#include <stdint.h>".to_string(),
        "".to_string(),
        "#define OKM_MODBUS_STRING_BYTE_CAPACITY 32U".to_string(),
        "#define OKM_MODBUS_STRING_REGISTER_WIDTH 17U".to_string(),
        "".to_string(),
        "typedef enum okm_modbus_exception_code {".to_string(),
        "    OKM_MODBUS_EXCEPTION_NONE = 0,".to_string(),
        "    OKM_MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 1,".to_string(),
        "    OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS = 2,".to_string(),
        "    OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE = 3,".to_string(),
        "    OKM_MODBUS_EXCEPTION_SLAVE_DEVICE_FAILURE = 4".to_string(),
        "} okm_modbus_exception_code_t;".to_string(),
        "".to_string(),
        "typedef struct okm_modbus_string32 {".to_string(),
        "    uint16_t length;".to_string(),
        "    char data[OKM_MODBUS_STRING_BYTE_CAPACITY + 1U];".to_string(),
        "} okm_modbus_string32_t;".to_string(),
        "".to_string(),
        "typedef struct okm_modbus_bytes32 {".to_string(),
        "    uint16_t length;".to_string(),
        "    uint8_t data[OKM_MODBUS_STRING_BYTE_CAPACITY];".to_string(),
        "} okm_modbus_bytes32_t;".to_string(),
        "".to_string(),
        "#endif /* OKM_MODBUS_COMMON_H */".to_string(),
        "".to_string(),
    ]
    .join("\n")
}

fn render_c_manifest_header(plan: &ContractPlan) -> String {
    let mut lines = vec![
        "/* 自动生成：Modbus 地址规划清单 */".to_string(),
        "#ifndef OKM_MODBUS_MANIFEST_H".to_string(),
        "#define OKM_MODBUS_MANIFEST_H".to_string(),
        "".to_string(),
        "#include \"okm_modbus_common.h\"".to_string(),
        "".to_string(),
        format!("#define OKM_MODBUS_TOTAL_COILS {}", plan.total_coils),
        format!(
            "#define OKM_MODBUS_TOTAL_DISCRETE_INPUTS {}",
            plan.total_discrete_inputs
        ),
        format!(
            "#define OKM_MODBUS_TOTAL_HOLDING_REGISTERS {}",
            plan.total_holding_registers
        ),
        format!(
            "#define OKM_MODBUS_TOTAL_INPUT_REGISTERS {}",
            plan.total_input_registers
        ),
        "".to_string(),
    ];

    for method in &plan.methods {
        let base = format!(
            "OKM_MODBUS_{}_{}",
            to_upper_snake_case(&method.interface_name),
            to_upper_snake_case(&method.method_name)
        );
        lines.push(format!(
            "#define {base}_START_ADDRESS {}",
            method.start_address
        ));
        lines.push(format!("#define {base}_QUANTITY {}", method.quantity));
        lines.push(format!(
            "#define {base}_AREA_{} 1",
            to_upper_snake_case(method.area_kind.c_label())
        ));
        lines.push(String::new());
    }
    lines.push("#endif /* OKM_MODBUS_MANIFEST_H */".to_string());
    lines.push(String::new());
    lines.join("\n")
}

fn render_c_service_header(plan: &ContractPlan, service: &crate::model::ContractService) -> String {
    let interface_name = normalize_type_name(&service.interface_name);
    let guard = format!("{}_SERVICE_H", to_upper_snake_case(&interface_name));
    let mut lines = vec![
        format!("/* 自动生成：{} 服务合同 */", interface_name),
        format!("#ifndef {guard}"),
        format!("#define {guard}"),
        "".to_string(),
        "#include \"okm_modbus_common.h\"".to_string(),
        "".to_string(),
    ];

    for method in plan
        .methods
        .iter()
        .filter(|method| method.interface_name == interface_name)
    {
        if let PlannedValue::Dto { type_name, items } = &method.planned_value {
            lines.push(format!("typedef struct {} {{", c_struct_name(type_name)));
            for item in items {
                lines.push(format!(
                    "    {} {};",
                    c_value_type(&item.value_type),
                    item.name
                ));
            }
            lines.push(format!("}} {};", c_struct_name(type_name)));
            lines.push(String::new());
        }
    }

    for method in plan
        .methods
        .iter()
        .filter(|method| method.interface_name == interface_name)
    {
        lines.push(format!(
            "int okm_bridge_{}({});",
            method.c_method_name,
            c_bridge_signature(method)
        ));
    }

    lines.push(String::new());
    lines.push(format!("#endif /* {guard} */"));
    lines.push(String::new());
    lines.join("\n")
}

fn render_c_dispatch_header() -> String {
    vec![
        "/* 自动生成：共享 Modbus dispatch 入口 */".to_string(),
        "#ifndef OKM_MODBUS_DISPATCH_H".to_string(),
        "#define OKM_MODBUS_DISPATCH_H".to_string(),
        "".to_string(),
        "#include \"okm_modbus_common.h\"".to_string(),
        "".to_string(),
        "int okm_modbus_read_discrete_inputs(uint16_t start_address, uint16_t quantity, uint8_t *dest_bits);"
            .to_string(),
        "int okm_modbus_read_input_registers(uint16_t start_address, uint16_t quantity, uint16_t *dest_registers);"
            .to_string(),
        "int okm_modbus_write_coils(uint16_t start_address, uint16_t quantity, const uint8_t *values);"
            .to_string(),
        "int okm_modbus_write_holding_registers(uint16_t start_address, uint16_t quantity, const uint16_t *values);"
            .to_string(),
        "".to_string(),
        "#endif /* OKM_MODBUS_DISPATCH_H */".to_string(),
        "".to_string(),
    ]
    .join("\n")
}

fn render_c_dispatch_source(plan: &ContractPlan) -> String {
    let mut lines = vec![
        "/* 自动生成：共享 Modbus dispatch 实现 */".to_string(),
        "#include \"okm_modbus_dispatch.h\"".to_string(),
        "#include \"okm_modbus_manifest.h\"".to_string(),
        "#include <string.h>".to_string(),
        "".to_string(),
    ];

    for service in &plan.services {
        lines.push(format!(
            "#include \"{}_service.h\"",
            to_snake_case(&service.interface_name)
        ));
    }
    lines.push(String::new());
    lines.push(
        "static void okm_modbus_encode_string32(uint16_t *registers, const okm_modbus_string32_t *value) {"
            .to_string(),
    );
    lines.push("    uint16_t length = value->length;".to_string());
    lines.push(
        "    if (length > OKM_MODBUS_STRING_BYTE_CAPACITY) { length = OKM_MODBUS_STRING_BYTE_CAPACITY; }"
            .to_string(),
    );
    lines.push("    registers[0] = length;".to_string());
    lines.push(
        "    memset(&registers[1], 0, sizeof(uint16_t) * (OKM_MODBUS_STRING_REGISTER_WIDTH - 1U));"
            .to_string(),
    );
    lines.push("    for (uint16_t index = 0; index < length; index += 2U) {".to_string());
    lines.push("        uint8_t high = (uint8_t)value->data[index];".to_string());
    lines.push(
        "        uint8_t low = (index + 1U < length) ? (uint8_t)value->data[index + 1U] : 0U;"
            .to_string(),
    );
    lines.push(
        "        registers[1U + (index / 2U)] = ((uint16_t)high << 8) | (uint16_t)low;".to_string(),
    );
    lines.push("    }".to_string());
    lines.push("}".to_string());
    lines.push(String::new());
    lines.push(
        "static void okm_modbus_encode_bytes32(uint16_t *registers, const okm_modbus_bytes32_t *value) {"
            .to_string(),
    );
    lines.push("    uint16_t length = value->length;".to_string());
    lines.push(
        "    if (length > OKM_MODBUS_STRING_BYTE_CAPACITY) { length = OKM_MODBUS_STRING_BYTE_CAPACITY; }"
            .to_string(),
    );
    lines.push("    registers[0] = length;".to_string());
    lines.push(
        "    memset(&registers[1], 0, sizeof(uint16_t) * (OKM_MODBUS_STRING_REGISTER_WIDTH - 1U));"
            .to_string(),
    );
    lines.push("    for (uint16_t index = 0; index < length; index += 2U) {".to_string());
    lines.push("        uint8_t high = value->data[index];".to_string());
    lines.push(
        "        uint8_t low = (index + 1U < length) ? value->data[index + 1U] : 0U;".to_string(),
    );
    lines.push(
        "        registers[1U + (index / 2U)] = ((uint16_t)high << 8) | (uint16_t)low;".to_string(),
    );
    lines.push("    }".to_string());
    lines.push("}".to_string());
    lines.push(String::new());
    lines.push(
        "static void okm_modbus_decode_string32(okm_modbus_string32_t *value, const uint16_t *registers) {"
            .to_string(),
    );
    lines.push("    uint16_t length = registers[0];".to_string());
    lines.push(
        "    if (length > OKM_MODBUS_STRING_BYTE_CAPACITY) { length = OKM_MODBUS_STRING_BYTE_CAPACITY; }"
            .to_string(),
    );
    lines.push("    value->length = length;".to_string());
    lines.push("    memset(value->data, 0, sizeof(value->data));".to_string());
    lines.push("    for (uint16_t index = 0; index < length; index += 2U) {".to_string());
    lines.push("        uint16_t register_value = registers[1U + (index / 2U)];".to_string());
    lines.push("        value->data[index] = (char)((register_value >> 8) & 0x00FFU);".to_string());
    lines.push("        if (index + 1U < length) {".to_string());
    lines.push(
        "            value->data[index + 1U] = (char)(register_value & 0x00FFU);".to_string(),
    );
    lines.push("        }".to_string());
    lines.push("    }".to_string());
    lines.push("}".to_string());
    lines.push(String::new());
    lines.push(
        "static void okm_modbus_decode_bytes32(okm_modbus_bytes32_t *value, const uint16_t *registers) {"
            .to_string(),
    );
    lines.push("    uint16_t length = registers[0];".to_string());
    lines.push(
        "    if (length > OKM_MODBUS_STRING_BYTE_CAPACITY) { length = OKM_MODBUS_STRING_BYTE_CAPACITY; }"
            .to_string(),
    );
    lines.push("    value->length = length;".to_string());
    lines.push("    memset(value->data, 0, sizeof(value->data));".to_string());
    lines.push("    for (uint16_t index = 0; index < length; index += 2U) {".to_string());
    lines.push("        uint16_t register_value = registers[1U + (index / 2U)];".to_string());
    lines.push(
        "        value->data[index] = (uint8_t)((register_value >> 8) & 0x00FFU);".to_string(),
    );
    lines.push("        if (index + 1U < length) {".to_string());
    lines.push(
        "            value->data[index + 1U] = (uint8_t)(register_value & 0x00FFU);".to_string(),
    );
    lines.push("        }".to_string());
    lines.push("    }".to_string());
    lines.push("}".to_string());
    lines.push(String::new());
    lines.push(render_c_read_bits_function(plan));
    lines.push(String::new());
    lines.push(render_c_read_registers_function(plan));
    lines.push(String::new());
    lines.push(render_c_write_bits_function(plan));
    lines.push(String::new());
    lines.push(render_c_write_registers_function(plan));
    lines.push(String::new());
    lines.join("\n")
}

fn render_c_read_bits_function(plan: &ContractPlan) -> String {
    if plan.total_discrete_inputs == 0 {
        return [
            "int okm_modbus_read_discrete_inputs(uint16_t start_address, uint16_t quantity, uint8_t *dest_bits) {",
            "    (void)start_address;",
            "    (void)quantity;",
            "    (void)dest_bits;",
            "    return OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS;",
            "}",
        ]
        .join("\n");
    }

    let mut lines = vec![
        "int okm_modbus_read_discrete_inputs(uint16_t start_address, uint16_t quantity, uint8_t *dest_bits) {"
            .to_string(),
        "    if (quantity == 0U || dest_bits == NULL) {".to_string(),
        "        return OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE;".to_string(),
        "    }".to_string(),
        format!(
            "    if ((uint32_t)start_address + (uint32_t)quantity > (uint32_t)OKM_MODBUS_TOTAL_DISCRETE_INPUTS) {{"
        ),
        "        return OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS;".to_string(),
        "    }".to_string(),
        format!(
            "    uint8_t area_buffer[OKM_MODBUS_TOTAL_DISCRETE_INPUTS > 0 ? OKM_MODBUS_TOTAL_DISCRETE_INPUTS : 1] = {{0}};"
        ),
    ];
    for method in plan
        .methods
        .iter()
        .filter(|method| matches!(method.area_kind, AreaKind::DiscreteInput))
    {
        lines.extend(render_c_populate_bit_area(method));
    }
    lines.push("    memcpy(dest_bits, &area_buffer[start_address], quantity);".to_string());
    lines.push("    return OKM_MODBUS_EXCEPTION_NONE;".to_string());
    lines.push("}".to_string());
    lines.join("\n")
}

fn render_c_populate_bit_area(method: &MethodPlan) -> Vec<String> {
    match &method.planned_value {
        PlannedValue::Dto { type_name, items } => {
            let mut lines = vec![
                format!(
                    "    {} {}_value;",
                    c_struct_name(type_name),
                    method.c_method_name
                ),
                format!(
                    "    if (okm_bridge_{}(&{}_value) != 0) {{",
                    method.c_method_name, method.c_method_name
                ),
                "        return OKM_MODBUS_EXCEPTION_SLAVE_DEVICE_FAILURE;".to_string(),
                "    }".to_string(),
            ];
            for item in items {
                lines.push(format!(
                    "    area_buffer[{}U] = {}_value.{} ? 1U : 0U;",
                    method.start_address + item.offset,
                    method.c_method_name,
                    item.name
                ));
            }
            lines
        }
        PlannedValue::Scalar { .. } => vec![
            "    bool value = false;".to_string(),
            format!(
                "    if (okm_bridge_{}(&value) != 0) {{",
                method.c_method_name
            ),
            "        return OKM_MODBUS_EXCEPTION_SLAVE_DEVICE_FAILURE;".to_string(),
            "    }".to_string(),
            format!(
                "    area_buffer[{}U] = value ? 1U : 0U;",
                method.start_address
            ),
        ],
        PlannedValue::Parameters { .. } => Vec::new(),
    }
}

fn render_c_read_registers_function(plan: &ContractPlan) -> String {
    if plan.total_input_registers == 0 {
        return [
            "int okm_modbus_read_input_registers(uint16_t start_address, uint16_t quantity, uint16_t *dest_registers) {",
            "    (void)start_address;",
            "    (void)quantity;",
            "    (void)dest_registers;",
            "    return OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS;",
            "}",
        ]
        .join("\n");
    }
    let mut lines = vec![
        "int okm_modbus_read_input_registers(uint16_t start_address, uint16_t quantity, uint16_t *dest_registers) {"
            .to_string(),
        "    if (quantity == 0U || dest_registers == NULL) {".to_string(),
        "        return OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE;".to_string(),
        "    }".to_string(),
        "    if ((uint32_t)start_address + (uint32_t)quantity > (uint32_t)OKM_MODBUS_TOTAL_INPUT_REGISTERS) {"
            .to_string(),
        "        return OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS;".to_string(),
        "    }".to_string(),
        "    uint16_t area_buffer[OKM_MODBUS_TOTAL_INPUT_REGISTERS > 0 ? OKM_MODBUS_TOTAL_INPUT_REGISTERS : 1] = {0};"
            .to_string(),
    ];
    for method in plan
        .methods
        .iter()
        .filter(|method| matches!(method.area_kind, AreaKind::InputRegister))
    {
        lines.extend(render_c_populate_register_area(method));
    }
    lines.push(
        "    memcpy(dest_registers, &area_buffer[start_address], sizeof(uint16_t) * quantity);"
            .to_string(),
    );
    lines.push("    return OKM_MODBUS_EXCEPTION_NONE;".to_string());
    lines.push("}".to_string());
    lines.join("\n")
}

fn render_c_populate_register_area(method: &MethodPlan) -> Vec<String> {
    match &method.planned_value {
        PlannedValue::Dto { type_name, items } => {
            let mut lines = vec![
                format!(
                    "    {} {}_value;",
                    c_struct_name(type_name),
                    method.c_method_name
                ),
                format!(
                    "    if (okm_bridge_{}(&{}_value) != 0) {{",
                    method.c_method_name, method.c_method_name
                ),
                "        return OKM_MODBUS_EXCEPTION_SLAVE_DEVICE_FAILURE;".to_string(),
                "    }".to_string(),
            ];
            for item in items {
                lines.extend(render_c_encode_item(
                    method.start_address + item.offset,
                    &format!("{}_value.{}", method.c_method_name, item.name),
                    item,
                ));
            }
            lines
        }
        PlannedValue::Scalar { item } => {
            let c_type = c_value_type(&item.value_type);
            let value_name = if matches!(item.value_type, ValueType::String | ValueType::Bytes) {
                format!("{c_type} value = {{0}};")
            } else {
                format!("{c_type} value = 0;")
            };
            let mut lines = vec![
                format!("    {value_name}"),
                format!(
                    "    if (okm_bridge_{}(&value) != 0) {{",
                    method.c_method_name
                ),
                "        return OKM_MODBUS_EXCEPTION_SLAVE_DEVICE_FAILURE;".to_string(),
                "    }".to_string(),
            ];
            lines.extend(render_c_encode_item(method.start_address, "value", item));
            lines
        }
        PlannedValue::Parameters { .. } => Vec::new(),
    }
}

fn render_c_encode_item(
    start_address: u16,
    value_expression: &str,
    item: &ItemPlan,
) -> Vec<String> {
    match item.value_type {
        ValueType::Boolean => vec![format!(
            "    area_buffer[{}U] = {} ? 1U : 0U;",
            start_address, value_expression
        )],
        ValueType::Int => vec![
            format!(
                "    area_buffer[{}U] = (uint16_t)((((uint32_t)({})) >> 16) & 0xFFFFU);",
                start_address, value_expression
            ),
            format!(
                "    area_buffer[{}U] = (uint16_t)(((uint32_t)({})) & 0xFFFFU);",
                start_address + 1,
                value_expression
            ),
        ],
        ValueType::String => vec![format!(
            "    okm_modbus_encode_string32(&area_buffer[{}U], &{});",
            start_address, value_expression
        )],
        ValueType::Bytes => vec![format!(
            "    okm_modbus_encode_bytes32(&area_buffer[{}U], &{});",
            start_address, value_expression
        )],
    }
}

fn render_c_write_bits_function(plan: &ContractPlan) -> String {
    let write_methods = plan
        .methods
        .iter()
        .filter(|method| matches!(method.area_kind, AreaKind::Coil))
        .collect::<Vec<_>>();
    if write_methods.is_empty() {
        return [
            "int okm_modbus_write_coils(uint16_t start_address, uint16_t quantity, const uint8_t *values) {",
            "    (void)start_address;",
            "    (void)quantity;",
            "    (void)values;",
            "    return OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS;",
            "}",
        ]
        .join("\n");
    }
    let mut lines = vec![
        "int okm_modbus_write_coils(uint16_t start_address, uint16_t quantity, const uint8_t *values) {"
            .to_string(),
        "    if (quantity == 0U || values == NULL) {".to_string(),
        "        return OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE;".to_string(),
        "    }".to_string(),
    ];
    for method in write_methods {
        let PlannedValue::Parameters { items } = &method.planned_value else {
            continue;
        };
        lines.push(format!(
            "    if (start_address == {}U && quantity == {}U) {{",
            method.start_address, method.quantity
        ));
        let call_arguments = items
            .iter()
            .enumerate()
            .map(|(index, _)| format!("values[{index}] != 0U"))
            .collect::<Vec<_>>()
            .join(", ");
        lines.push(format!(
            "        return okm_bridge_{}({}) == 0 ? OKM_MODBUS_EXCEPTION_NONE : OKM_MODBUS_EXCEPTION_SLAVE_DEVICE_FAILURE;",
            method.c_method_name, call_arguments
        ));
        lines.push("    }".to_string());
    }
    lines.push("    return OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS;".to_string());
    lines.push("}".to_string());
    lines.join("\n")
}

fn render_c_write_registers_function(plan: &ContractPlan) -> String {
    let write_methods = plan
        .methods
        .iter()
        .filter(|method| matches!(method.area_kind, AreaKind::HoldingRegister))
        .collect::<Vec<_>>();
    if write_methods.is_empty() {
        return [
            "int okm_modbus_write_holding_registers(uint16_t start_address, uint16_t quantity, const uint16_t *values) {",
            "    (void)start_address;",
            "    (void)quantity;",
            "    (void)values;",
            "    return OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS;",
            "}",
        ]
        .join("\n");
    }
    let mut lines = vec![
        "int okm_modbus_write_holding_registers(uint16_t start_address, uint16_t quantity, const uint16_t *values) {"
            .to_string(),
        "    if (quantity == 0U || values == NULL) {".to_string(),
        "        return OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE;".to_string(),
        "    }".to_string(),
    ];
    for method in write_methods {
        let PlannedValue::Parameters { items } = &method.planned_value else {
            continue;
        };
        lines.push(format!(
            "    if (start_address == {}U && quantity == {}U) {{",
            method.start_address, method.quantity
        ));
        for item in items {
            let variable_name = format!("decoded_{}", item.name);
            lines.push(c_decode_variable_declaration(item, &variable_name));
            lines.extend(render_c_decode_item(item, "values", &variable_name));
        }
        let call_arguments = items
            .iter()
            .map(|item| {
                if matches!(item.value_type, ValueType::String | ValueType::Bytes) {
                    format!("&decoded_{}", item.name)
                } else {
                    format!("decoded_{}", item.name)
                }
            })
            .collect::<Vec<_>>()
            .join(", ");
        lines.push(format!(
            "        return okm_bridge_{}({}) == 0 ? OKM_MODBUS_EXCEPTION_NONE : OKM_MODBUS_EXCEPTION_SLAVE_DEVICE_FAILURE;",
            method.c_method_name, call_arguments
        ));
        lines.push("    }".to_string());
    }
    lines.push("    return OKM_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS;".to_string());
    lines.push("}".to_string());
    lines.join("\n")
}

fn c_decode_variable_declaration(item: &ItemPlan, variable_name: &str) -> String {
    match item.value_type {
        ValueType::Boolean => format!("        bool {variable_name} = false;"),
        ValueType::Int => format!("        int32_t {variable_name} = 0;"),
        ValueType::String => format!("        okm_modbus_string32_t {variable_name} = {{0}};"),
        ValueType::Bytes => format!("        okm_modbus_bytes32_t {variable_name} = {{0}};"),
    }
}

fn render_c_decode_item(item: &ItemPlan, buffer_name: &str, variable_name: &str) -> Vec<String> {
    match item.value_type {
        ValueType::Boolean => vec![format!(
            "        {variable_name} = {buffer_name}[{}U] != 0U;",
            item.offset
        )],
        ValueType::Int => vec![format!(
            "        {variable_name} = (int32_t)(((uint32_t){buffer_name}[{}U] << 16) | (uint32_t){buffer_name}[{}U]);",
            item.offset,
            item.offset + 1
        )],
        ValueType::String => vec![format!(
            "        okm_modbus_decode_string32(&{variable_name}, &{buffer_name}[{}U]);",
            item.offset
        )],
        ValueType::Bytes => vec![format!(
            "        okm_modbus_decode_bytes32(&{variable_name}, &{buffer_name}[{}U]);",
            item.offset
        )],
    }
}

fn render_c_transport_header(transport_label: &str, segment: &str) -> String {
    let guard = format!("OKM_MODBUS_{}_H", to_upper_snake_case(segment));
    let request_type = if segment == "rtu" { "RTU" } else { "TCP" };
    vec![
        format!("/* 自动生成：{transport_label} transport 入口 */"),
        format!("#ifndef {guard}"),
        format!("#define {guard}"),
        "".to_string(),
        "#include <stddef.h>".to_string(),
        "#include <stdint.h>".to_string(),
        "#include \"okm_modbus_common.h\"".to_string(),
        "".to_string(),
        format!(
            "int okm_modbus_{}_handle_request(const uint8_t *request_adu, size_t request_length, uint8_t *response_adu, size_t response_capacity);",
            segment
        ),
        "".to_string(),
        format!("/* 该入口负责完整解析 {request_type} 请求帧并生成响应帧。 */"),
        "".to_string(),
        format!("#endif /* {guard} */"),
        "".to_string(),
    ]
    .join("\n")
}

fn render_c_transport_source(plan: &ContractPlan, transport: &TransportKind) -> String {
    match transport {
        TransportKind::Rtu => render_c_rtu_source(plan),
        TransportKind::Tcp => render_c_tcp_source(plan),
    }
}

fn render_c_rtu_source(_plan: &ContractPlan) -> String {
    [
        "/* 自动生成：RTU transport 入口 */",
        "#include \"rtu/okm_modbus_rtu.h\"",
        "#include \"okm_modbus_dispatch.h\"",
        "#include <string.h>",
        "",
        "static uint16_t okm_modbus_crc16(const uint8_t *payload, size_t length) {",
        "    uint16_t crc = 0xFFFFU;",
        "    for (size_t index = 0; index < length; ++index) {",
        "        crc ^= (uint16_t)payload[index];",
        "        for (uint8_t bit = 0; bit < 8U; ++bit) {",
        "            uint16_t lsb = crc & 0x0001U;",
        "            crc >>= 1U;",
        "            if (lsb == 1U) {",
        "                crc ^= 0xA001U;",
        "            }",
        "        }",
        "    }",
        "    return crc;",
        "}",
        "",
        "static void okm_modbus_append_crc(uint8_t *frame, size_t *length) {",
        "    uint16_t crc = okm_modbus_crc16(frame, *length);",
        "    frame[(*length)++] = (uint8_t)(crc & 0x00FFU);",
        "    frame[(*length)++] = (uint8_t)((crc >> 8) & 0x00FFU);",
        "}",
        "",
        "static size_t okm_modbus_build_exception(uint8_t slave, uint8_t function_code, okm_modbus_exception_code_t exception, uint8_t *response_adu) {",
        "    size_t response_length = 0U;",
        "    response_adu[response_length++] = slave;",
        "    response_adu[response_length++] = (uint8_t)(function_code | 0x80U);",
        "    response_adu[response_length++] = (uint8_t)exception;",
        "    okm_modbus_append_crc(response_adu, &response_length);",
        "    return response_length;",
        "}",
        "",
        "int okm_modbus_rtu_handle_request(const uint8_t *request_adu, size_t request_length, uint8_t *response_adu, size_t response_capacity) {",
        "    if (request_adu == NULL || response_adu == NULL || request_length < 8U || response_capacity < 5U) {",
        "        return -1;",
        "    }",
        "    uint16_t expected_crc = (uint16_t)request_adu[request_length - 2U] | ((uint16_t)request_adu[request_length - 1U] << 8);",
        "    uint16_t actual_crc = okm_modbus_crc16(request_adu, request_length - 2U);",
        "    if (expected_crc != actual_crc) {",
        "        return -1;",
        "    }",
        "    uint8_t slave = request_adu[0];",
        "    uint8_t function_code = request_adu[1];",
        "    uint16_t start_address = (uint16_t)((request_adu[2] << 8) | request_adu[3]);",
        "    uint16_t quantity = (uint16_t)((request_adu[4] << 8) | request_adu[5]);",
        "    okm_modbus_exception_code_t exception = OKM_MODBUS_EXCEPTION_ILLEGAL_FUNCTION;",
        "    size_t response_length = 0U;",
        "    if (function_code == 0x02U) {",
        "        uint8_t values[256] = {0};",
        "        exception = (okm_modbus_exception_code_t)okm_modbus_read_discrete_inputs(start_address, quantity, values);",
        "        if (exception == OKM_MODBUS_EXCEPTION_NONE) {",
        "            uint8_t byte_count = (uint8_t)((quantity + 7U) / 8U);",
        "            response_adu[response_length++] = slave;",
        "            response_adu[response_length++] = function_code;",
        "            response_adu[response_length++] = byte_count;",
        "            for (uint16_t index = 0; index < quantity; ++index) {",
        "                size_t byte_index = response_length + (size_t)(index / 8U);",
        "                if ((index % 8U) == 0U) {",
        "                    response_adu[byte_index] = 0U;",
        "                }",
        "                if (values[index] != 0U) {",
        "                    response_adu[byte_index] |= (uint8_t)(1U << (index % 8U));",
        "                }",
        "            }",
        "            response_length += byte_count;",
        "            okm_modbus_append_crc(response_adu, &response_length);",
        "            return (int)response_length;",
        "        }",
        "    }",
        "    if (function_code == 0x04U) {",
        "        uint16_t values[256] = {0};",
        "        exception = (okm_modbus_exception_code_t)okm_modbus_read_input_registers(start_address, quantity, values);",
        "        if (exception == OKM_MODBUS_EXCEPTION_NONE) {",
        "            response_adu[response_length++] = slave;",
        "            response_adu[response_length++] = function_code;",
        "            response_adu[response_length++] = (uint8_t)(quantity * 2U);",
        "            for (uint16_t index = 0; index < quantity; ++index) {",
        "                response_adu[response_length++] = (uint8_t)((values[index] >> 8) & 0x00FFU);",
        "                response_adu[response_length++] = (uint8_t)(values[index] & 0x00FFU);",
        "            }",
        "            okm_modbus_append_crc(response_adu, &response_length);",
        "            return (int)response_length;",
        "        }",
        "    }",
        "    if (function_code == 0x05U) {",
        "        uint8_t coil_value = request_adu[4] == 0xFFU ? 1U : 0U;",
        "        exception = (okm_modbus_exception_code_t)okm_modbus_write_coils(start_address, 1U, &coil_value);",
        "        if (exception == OKM_MODBUS_EXCEPTION_NONE) {",
        "            memcpy(response_adu, request_adu, request_length);",
        "            return (int)request_length;",
        "        }",
        "    }",
        "    if (function_code == 0x0FU) {",
        "        uint8_t byte_count = request_adu[6];",
        "        uint8_t values[256] = {0};",
        "        for (uint16_t index = 0; index < quantity; ++index) {",
        "            uint8_t source = request_adu[7U + (index / 8U)];",
        "            values[index] = (uint8_t)((source >> (index % 8U)) & 0x01U);",
        "        }",
        "        (void)byte_count;",
        "        exception = (okm_modbus_exception_code_t)okm_modbus_write_coils(start_address, quantity, values);",
        "        if (exception == OKM_MODBUS_EXCEPTION_NONE) {",
        "            response_adu[0] = slave;",
        "            response_adu[1] = function_code;",
        "            response_adu[2] = request_adu[2];",
        "            response_adu[3] = request_adu[3];",
        "            response_adu[4] = request_adu[4];",
        "            response_adu[5] = request_adu[5];",
        "            response_length = 6U;",
        "            okm_modbus_append_crc(response_adu, &response_length);",
        "            return (int)response_length;",
        "        }",
        "    }",
        "    if (function_code == 0x06U) {",
        "        uint16_t value = (uint16_t)((request_adu[4] << 8) | request_adu[5]);",
        "        exception = (okm_modbus_exception_code_t)okm_modbus_write_holding_registers(start_address, 1U, &value);",
        "        if (exception == OKM_MODBUS_EXCEPTION_NONE) {",
        "            memcpy(response_adu, request_adu, request_length);",
        "            return (int)request_length;",
        "        }",
        "    }",
        "    if (function_code == 0x10U) {",
        "        uint8_t byte_count = request_adu[6];",
        "        uint16_t values[256] = {0};",
        "        for (uint16_t index = 0; index < quantity; ++index) {",
        "            size_t source_index = 7U + ((size_t)index * 2U);",
        "            values[index] = (uint16_t)((request_adu[source_index] << 8) | request_adu[source_index + 1U]);",
        "        }",
        "        (void)byte_count;",
        "        exception = (okm_modbus_exception_code_t)okm_modbus_write_holding_registers(start_address, quantity, values);",
        "        if (exception == OKM_MODBUS_EXCEPTION_NONE) {",
        "            response_adu[0] = slave;",
        "            response_adu[1] = function_code;",
        "            response_adu[2] = request_adu[2];",
        "            response_adu[3] = request_adu[3];",
        "            response_adu[4] = request_adu[4];",
        "            response_adu[5] = request_adu[5];",
        "            response_length = 6U;",
        "            okm_modbus_append_crc(response_adu, &response_length);",
        "            return (int)response_length;",
        "        }",
        "    }",
        "    return (int)okm_modbus_build_exception(slave, function_code, exception, response_adu);",
        "}",
        "",
    ]
    .join("\n")
}

fn render_c_tcp_source(_plan: &ContractPlan) -> String {
    [
        "/* 自动生成：TCP transport 入口 */",
        "#include \"tcp/okm_modbus_tcp.h\"",
        "#include \"okm_modbus_dispatch.h\"",
        "#include <string.h>",
        "",
        "static size_t okm_modbus_tcp_build_exception(const uint8_t *request_adu, uint8_t function_code, okm_modbus_exception_code_t exception, uint8_t *response_adu) {",
        "    memcpy(response_adu, request_adu, 7U);",
        "    response_adu[7] = (uint8_t)(function_code | 0x80U);",
        "    response_adu[8] = (uint8_t)exception;",
        "    response_adu[4] = 0x00U;",
        "    response_adu[5] = 0x03U;",
        "    return 9U;",
        "}",
        "",
        "int okm_modbus_tcp_handle_request(const uint8_t *request_adu, size_t request_length, uint8_t *response_adu, size_t response_capacity) {",
        "    if (request_adu == NULL || response_adu == NULL || request_length < 12U || response_capacity < 9U) {",
        "        return -1;",
        "    }",
        "    uint8_t function_code = request_adu[7];",
        "    uint16_t start_address = (uint16_t)((request_adu[8] << 8) | request_adu[9]);",
        "    uint16_t quantity = (uint16_t)((request_adu[10] << 8) | request_adu[11]);",
        "    okm_modbus_exception_code_t exception = OKM_MODBUS_EXCEPTION_ILLEGAL_FUNCTION;",
        "    memcpy(response_adu, request_adu, 7U);",
        "    if (function_code == 0x02U) {",
        "        uint8_t values[256] = {0};",
        "        exception = (okm_modbus_exception_code_t)okm_modbus_read_discrete_inputs(start_address, quantity, values);",
        "        if (exception == OKM_MODBUS_EXCEPTION_NONE) {",
        "            uint8_t byte_count = (uint8_t)((quantity + 7U) / 8U);",
        "            response_adu[7] = function_code;",
        "            response_adu[8] = byte_count;",
        "            memset(&response_adu[9], 0, byte_count);",
        "            for (uint16_t index = 0; index < quantity; ++index) {",
        "                if (values[index] != 0U) {",
        "                    response_adu[9U + (index / 8U)] |= (uint8_t)(1U << (index % 8U));",
        "                }",
        "            }",
        "            response_adu[4] = 0x00U;",
        "            response_adu[5] = (uint8_t)(3U + byte_count);",
        "            return (int)(9U + byte_count);",
        "        }",
        "    }",
        "    if (function_code == 0x04U) {",
        "        uint16_t values[256] = {0};",
        "        exception = (okm_modbus_exception_code_t)okm_modbus_read_input_registers(start_address, quantity, values);",
        "        if (exception == OKM_MODBUS_EXCEPTION_NONE) {",
        "            response_adu[7] = function_code;",
        "            response_adu[8] = (uint8_t)(quantity * 2U);",
        "            size_t response_length = 9U;",
        "            for (uint16_t index = 0; index < quantity; ++index) {",
        "                response_adu[response_length++] = (uint8_t)((values[index] >> 8) & 0x00FFU);",
        "                response_adu[response_length++] = (uint8_t)(values[index] & 0x00FFU);",
        "            }",
        "            response_adu[4] = (uint8_t)(((response_length - 6U) >> 8) & 0x00FFU);",
        "            response_adu[5] = (uint8_t)((response_length - 6U) & 0x00FFU);",
        "            return (int)response_length;",
        "        }",
        "    }",
        "    if (function_code == 0x05U) {",
        "        uint8_t coil_value = request_adu[10] == 0xFFU ? 1U : 0U;",
        "        exception = (okm_modbus_exception_code_t)okm_modbus_write_coils(start_address, 1U, &coil_value);",
        "        if (exception == OKM_MODBUS_EXCEPTION_NONE) {",
        "            memcpy(response_adu, request_adu, 12U);",
        "            return 12;",
        "        }",
        "    }",
        "    if (function_code == 0x0FU) {",
        "        uint8_t values[256] = {0};",
        "        for (uint16_t index = 0; index < quantity; ++index) {",
        "            uint8_t source = request_adu[13U + (index / 8U)];",
        "            values[index] = (uint8_t)((source >> (index % 8U)) & 0x01U);",
        "        }",
        "        exception = (okm_modbus_exception_code_t)okm_modbus_write_coils(start_address, quantity, values);",
        "        if (exception == OKM_MODBUS_EXCEPTION_NONE) {",
        "            memcpy(response_adu, request_adu, 12U);",
        "            return 12;",
        "        }",
        "    }",
        "    if (function_code == 0x06U) {",
        "        uint16_t value = (uint16_t)((request_adu[10] << 8) | request_adu[11]);",
        "        exception = (okm_modbus_exception_code_t)okm_modbus_write_holding_registers(start_address, 1U, &value);",
        "        if (exception == OKM_MODBUS_EXCEPTION_NONE) {",
        "            memcpy(response_adu, request_adu, 12U);",
        "            return 12;",
        "        }",
        "    }",
        "    if (function_code == 0x10U) {",
        "        uint16_t values[256] = {0};",
        "        for (uint16_t index = 0; index < quantity; ++index) {",
        "            size_t source_index = 13U + ((size_t)index * 2U);",
        "            values[index] = (uint16_t)((request_adu[source_index] << 8) | request_adu[source_index + 1U]);",
        "        }",
        "        exception = (okm_modbus_exception_code_t)okm_modbus_write_holding_registers(start_address, quantity, values);",
        "        if (exception == OKM_MODBUS_EXCEPTION_NONE) {",
        "            memcpy(response_adu, request_adu, 12U);",
        "            return 12;",
        "        }",
        "    }",
        "    return (int)okm_modbus_tcp_build_exception(request_adu, function_code, exception, response_adu);",
        "}",
        "",
    ]
    .join("\n")
}

fn c_struct_name(type_name: &str) -> String {
    format!("{}_t", to_snake_case(type_name))
}

fn c_value_type(value_type: &ValueType) -> &'static str {
    match value_type {
        ValueType::Boolean => "bool",
        ValueType::Int => "int32_t",
        ValueType::String => "okm_modbus_string32_t",
        ValueType::Bytes => "okm_modbus_bytes32_t",
    }
}

fn c_bridge_signature(method: &MethodPlan) -> String {
    match &method.planned_value {
        PlannedValue::Dto { type_name, .. } => {
            format!("{} *out_value", c_struct_name(type_name))
        }
        PlannedValue::Scalar { item } => {
            format!("{} *out_value", c_value_type(&item.value_type))
        }
        PlannedValue::Parameters { items } => items
            .iter()
            .map(|item| match item.value_type {
                ValueType::Boolean => format!("bool {}", item.name),
                ValueType::Int => format!("int32_t {}", item.name),
                ValueType::String => format!("const okm_modbus_string32_t *{}", item.name),
                ValueType::Bytes => format!("const okm_modbus_bytes32_t *{}", item.name),
            })
            .collect::<Vec<_>>()
            .join(", "),
    }
}
