use crate::debugger::debugee::dwarf::r#type::{
    ArrayType, ComplexType, MemberLocation, StructureMember, TypeDeclaration, TypeId,
};
use crate::debugger::variable::value::Value;
use indexmap::IndexMap;
use serde_json::Value as JsonValue;

#[derive(Debug, thiserror::Error)]
pub enum SerializeError {
    #[error("unsupported input: {0}")]
    UnsupportedInput(String),
    #[error("missing required field: {0}")]
    MissingField(String),
    #[error("unexpected input for type: {0}")]
    UnexpectedInput(String),
    #[error("unknown type id")]
    UnknownType,
    #[error("unknown type size for type id {0:?}")]
    UnknownTypeSize(TypeId),
    #[error("enum variant '{0}' not found")]
    EnumVariantNotFound(String),
    #[error("enum discriminant type missing")]
    EnumDiscriminantMissing,
    #[error("member offset for '{0}' not available")]
    MemberOffsetMissing(String),
    #[error("array element type missing")]
    ArrayElementTypeMissing,
    #[error("array length mismatch: expected {expected}, got {actual}")]
    ArrayLengthMismatch { expected: usize, actual: usize },
    #[error("value size mismatch: expected {expected}, got {actual}")]
    SizeMismatch { expected: usize, actual: usize },
    #[error("scalar parse failed: {0}")]
    ScalarParse(String),
}

#[derive(Clone, Debug)]
pub struct WriteOffset {
    pub path: String,
    pub offset: usize,
    pub size: usize,
}

#[derive(Clone, Debug)]
pub struct SerializedValue {
    pub bytes: Vec<u8>,
    pub size: usize,
    pub offsets: Vec<WriteOffset>,
}

#[derive(Clone, Debug)]
enum InputValue {
    Scalar(String),
    Array(Vec<InputValue>),
    Object(IndexMap<String, InputValue>),
    EnumVariant {
        name: String,
        payload: Option<Box<InputValue>>,
    },
}

pub fn serialize_dap_value(
    input: &str,
    type_graph: &ComplexType,
    type_id: TypeId,
    runtime_value: Option<&Value>,
) -> Result<SerializedValue, SerializeError> {
    let input = parse_input_value(input)?;
    let mut offsets = Vec::new();
    let bytes =
        serialize_value_inner(&input, type_graph, type_id, runtime_value, "", &mut offsets)?;
    let size = bytes.len();
    Ok(SerializedValue {
        bytes,
        size,
        offsets,
    })
}

fn parse_input_value(input: &str) -> Result<InputValue, SerializeError> {
    let trimmed = input.trim();
    if trimmed.is_empty() {
        return Err(SerializeError::UnsupportedInput("empty input".to_string()));
    }

    if let Ok(json) = serde_json::from_str::<JsonValue>(trimmed) {
        return Ok(input_from_json(&json));
    }

    if let Some(enum_value) = parse_enum_syntax(trimmed)? {
        return Ok(enum_value);
    }

    if let Some(tuple) = parse_tuple_syntax(trimmed)? {
        return Ok(tuple);
    }

    if let Some(obj) = parse_object_syntax(trimmed)? {
        return Ok(obj);
    }

    Ok(InputValue::Scalar(trimmed.to_string()))
}

fn parse_enum_syntax(input: &str) -> Result<Option<InputValue>, SerializeError> {
    let mut chars = input.chars();
    let first = chars.next();
    let Some(first) = first else {
        return Ok(None);
    };
    if !first.is_ascii_alphabetic() && first != '_' {
        return Ok(None);
    }

    let mut ident = String::new();
    ident.push(first);
    let mut rest_start = first.len_utf8();
    for ch in input[rest_start..].chars() {
        if ch.is_ascii_alphanumeric() || ch == '_' {
            ident.push(ch);
            rest_start += ch.len_utf8();
        } else {
            break;
        }
    }

    let rest = input[rest_start..].trim_start();
    if rest.is_empty() {
        return Ok(None);
    }

    let payload = if rest.starts_with('(') && rest.ends_with(')') {
        let inner = &rest[1..rest.len() - 1];
        Some(Box::new(parse_input_value(inner)?))
    } else if rest.starts_with('{') && rest.ends_with('}') {
        let inner = &rest[1..rest.len() - 1];
        Some(Box::new(parse_object_body(inner)?))
    } else {
        return Ok(None);
    };

    Ok(Some(InputValue::EnumVariant {
        name: ident,
        payload,
    }))
}

fn parse_tuple_syntax(input: &str) -> Result<Option<InputValue>, SerializeError> {
    let trimmed = input.trim();
    if !(trimmed.starts_with('(') && trimmed.ends_with(')')) {
        return Ok(None);
    }
    let inner = &trimmed[1..trimmed.len() - 1];
    let items = split_top_level(inner)
        .into_iter()
        .filter(|part| !part.trim().is_empty())
        .map(|part| parse_input_value(part.trim()))
        .collect::<Result<Vec<_>, _>>()?;
    Ok(Some(InputValue::Array(items)))
}

fn parse_object_syntax(input: &str) -> Result<Option<InputValue>, SerializeError> {
    let trimmed = input.trim();
    if !(trimmed.starts_with('{') && trimmed.ends_with('}')) {
        return Ok(None);
    }
    let inner = &trimmed[1..trimmed.len() - 1];
    Ok(Some(parse_object_body(inner)?))
}

fn parse_object_body(body: &str) -> Result<InputValue, SerializeError> {
    let mut out = IndexMap::new();
    for part in split_top_level(body) {
        let part = part.trim();
        if part.is_empty() {
            continue;
        }
        let (key, value) = split_key_value(part)?;
        let key = key.trim().trim_matches('"').trim_matches('\'');
        let value = parse_input_value(value.trim())?;
        out.insert(key.to_string(), value);
    }
    Ok(InputValue::Object(out))
}

fn split_key_value(input: &str) -> Result<(&str, &str), SerializeError> {
    let mut depth = 0usize;
    let mut in_str = None;
    for (idx, ch) in input.char_indices() {
        match ch {
            '"' | '\'' => {
                if in_str == Some(ch) {
                    in_str = None;
                } else if in_str.is_none() {
                    in_str = Some(ch);
                }
            }
            '{' | '[' | '(' if in_str.is_none() => depth += 1,
            '}' | ']' | ')' if in_str.is_none() => depth = depth.saturating_sub(1),
            ':' if in_str.is_none() && depth == 0 => {
                let (k, v) = input.split_at(idx);
                return Ok((k, &v[1..]));
            }
            _ => {}
        }
    }
    Err(SerializeError::UnsupportedInput(format!(
        "expected key:value in '{input}'"
    )))
}

fn split_top_level(input: &str) -> Vec<&str> {
    let mut parts = Vec::new();
    let mut depth = 0usize;
    let mut in_str: Option<char> = None;
    let mut start = 0usize;
    let mut prev_char = '\0';

    for (idx, ch) in input.char_indices() {
        if let Some(quote) = in_str {
            if ch == quote && prev_char != '\\' {
                in_str = None;
            }
            prev_char = ch;
            continue;
        }

        match ch {
            '\'' | '"' => in_str = Some(ch),
            '{' | '[' | '(' => depth += 1,
            '}' | ']' | ')' => depth = depth.saturating_sub(1),
            ',' if depth == 0 => {
                parts.push(&input[start..idx]);
                start = idx + ch.len_utf8();
            }
            _ => {}
        }
        prev_char = ch;
    }

    if start <= input.len() {
        parts.push(&input[start..]);
    }

    parts
}

fn input_from_json(value: &JsonValue) -> InputValue {
    match value {
        JsonValue::Null => InputValue::Scalar("null".to_string()),
        JsonValue::Bool(b) => InputValue::Scalar(b.to_string()),
        JsonValue::Number(num) => InputValue::Scalar(num.to_string()),
        JsonValue::String(s) => InputValue::Scalar(s.clone()),
        JsonValue::Array(items) => InputValue::Array(items.iter().map(input_from_json).collect()),
        JsonValue::Object(map) => InputValue::Object(
            map.iter()
                .map(|(k, v)| (k.clone(), input_from_json(v)))
                .collect(),
        ),
    }
}

fn serialize_value_inner(
    input: &InputValue,
    type_graph: &ComplexType,
    type_id: TypeId,
    runtime_value: Option<&Value>,
    path: &str,
    offsets: &mut Vec<WriteOffset>,
) -> Result<Vec<u8>, SerializeError> {
    let mut ctx = SerializeContext {
        input,
        type_graph,
        type_id,
        runtime_value,
        path,
        offsets,
    };
    let decl = type_graph
        .types
        .get(&type_id)
        .ok_or(SerializeError::UnknownType)?;
    match decl {
        TypeDeclaration::Scalar(scalar) => serialize_scalar_value(input, scalar),
        TypeDeclaration::Pointer { .. } => serialize_pointer_value(input),
        TypeDeclaration::Array(array) => serialize_array_value(&mut ctx, array),
        TypeDeclaration::Structure {
            byte_size, members, ..
        } => serialize_struct_value(&mut ctx, *byte_size, members),
        TypeDeclaration::Union {
            byte_size, members, ..
        } => serialize_union_value(&mut ctx, *byte_size, members),
        TypeDeclaration::CStyleEnum {
            byte_size,
            discr_type,
            enumerators,
            ..
        } => serialize_c_enum_value(input, type_graph, *byte_size, *discr_type, enumerators),
        TypeDeclaration::RustEnum {
            byte_size,
            discr_type,
            enumerators,
            ..
        } => serialize_rust_enum_value(&mut ctx, *byte_size, discr_type.as_deref(), enumerators),
        TypeDeclaration::Subroutine { .. } => serialize_pointer_value(input),
        TypeDeclaration::ModifiedType { inner, .. } => {
            let inner = inner.ok_or(SerializeError::UnknownType)?;
            serialize_value_inner(input, type_graph, inner, runtime_value, path, offsets)
        }
    }
}

struct SerializeContext<'a> {
    input: &'a InputValue,
    type_graph: &'a ComplexType,
    type_id: TypeId,
    runtime_value: Option<&'a Value>,
    path: &'a str,
    offsets: &'a mut Vec<WriteOffset>,
}

fn serialize_scalar_value(
    input: &InputValue,
    scalar: &crate::debugger::debugee::dwarf::r#type::ScalarType,
) -> Result<Vec<u8>, SerializeError> {
    let input = match input {
        InputValue::Scalar(s) => s.as_str(),
        _ => {
            return Err(SerializeError::UnexpectedInput(
                "expected scalar".to_string(),
            ));
        }
    };
    let byte_size = scalar.byte_size.unwrap_or(0) as usize;
    let encoding = scalar.encoding;

    fn parse_i128(input: &str) -> Result<i128, SerializeError> {
        if let Some(hex) = input
            .strip_prefix("0x")
            .or_else(|| input.strip_prefix("0X"))
        {
            i128::from_str_radix(hex, 16).map_err(|e| SerializeError::ScalarParse(e.to_string()))
        } else {
            input
                .parse::<i128>()
                .map_err(|e| SerializeError::ScalarParse(e.to_string()))
        }
    }

    fn parse_u128(input: &str) -> Result<u128, SerializeError> {
        if let Some(hex) = input
            .strip_prefix("0x")
            .or_else(|| input.strip_prefix("0X"))
        {
            u128::from_str_radix(hex, 16).map_err(|e| SerializeError::ScalarParse(e.to_string()))
        } else {
            input
                .parse::<u128>()
                .map_err(|e| SerializeError::ScalarParse(e.to_string()))
        }
    }

    let bytes = match encoding {
        Some(gimli::DW_ATE_float) => match byte_size {
            4 => Ok(input
                .parse::<f32>()
                .map_err(|e| SerializeError::ScalarParse(e.to_string()))?
                .to_le_bytes()
                .to_vec()),
            8 => Ok(input
                .parse::<f64>()
                .map_err(|e| SerializeError::ScalarParse(e.to_string()))?
                .to_le_bytes()
                .to_vec()),
            _ => Err(SerializeError::ScalarParse(format!(
                "unsupported float size {byte_size}"
            ))),
        },
        Some(gimli::DW_ATE_boolean) => {
            let value = match input {
                "true" | "True" | "TRUE" | "1" => true,
                "false" | "False" | "FALSE" | "0" => false,
                _ => {
                    return Err(SerializeError::ScalarParse(format!(
                        "expected bool, got '{input}'"
                    )));
                }
            };
            Ok(vec![if value { 1 } else { 0 }])
        }
        Some(gimli::DW_ATE_UTF) | Some(gimli::DW_ATE_ASCII) => {
            let ch =
                if let Some(stripped) = input.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
                {
                    stripped.chars().next().ok_or_else(|| {
                        SerializeError::ScalarParse("empty char literal".to_string())
                    })?
                } else if input.chars().count() == 1 {
                    input.chars().next().unwrap()
                } else {
                    return Err(SerializeError::ScalarParse(
                        "expected char literal".to_string(),
                    ));
                };
            Ok((ch as u32).to_le_bytes().to_vec())
        }
        Some(gimli::DW_ATE_signed) | Some(gimli::DW_ATE_signed_char) => {
            let value = parse_i128(input)?;
            int_to_bytes(value as i128, byte_size)
        }
        Some(gimli::DW_ATE_unsigned)
        | Some(gimli::DW_ATE_unsigned_char)
        | Some(gimli::DW_ATE_address) => {
            let value = parse_u128(input)?;
            uint_to_bytes(value, byte_size)
        }
        _ => {
            let value = parse_i128(input)?;
            int_to_bytes(value, byte_size)
        }
    }?;

    Ok(bytes)
}

fn serialize_pointer_value(input: &InputValue) -> Result<Vec<u8>, SerializeError> {
    let input = match input {
        InputValue::Scalar(s) => s.as_str(),
        _ => {
            return Err(SerializeError::UnexpectedInput(
                "expected pointer scalar".to_string(),
            ));
        }
    };
    let addr = if let Some(hex) = input
        .strip_prefix("0x")
        .or_else(|| input.strip_prefix("0X"))
    {
        usize::from_str_radix(hex, 16).map_err(|e| SerializeError::ScalarParse(e.to_string()))?
    } else {
        input
            .parse::<usize>()
            .map_err(|e| SerializeError::ScalarParse(e.to_string()))?
    };
    Ok(addr.to_le_bytes().to_vec())
}

fn serialize_struct_value(
    ctx: &mut SerializeContext<'_>,
    byte_size: Option<u64>,
    members: &[StructureMember],
) -> Result<Vec<u8>, SerializeError> {
    let size = byte_size.ok_or(SerializeError::UnknownTypeSize(ctx.type_id))?;
    let mut buffer = vec![0u8; size as usize];

    let input_map = match ctx.input {
        InputValue::Object(map) => Some(map),
        _ => None,
    };
    let input_array = match ctx.input {
        InputValue::Array(items) => Some(items),
        _ => None,
    };

    for (index, member) in members.iter().enumerate() {
        let member_input = if let Some(name) = member.name.as_deref() {
            input_map
                .and_then(|map| map.get(name))
                .ok_or_else(|| SerializeError::MissingField(name.to_string()))?
        } else {
            input_array
                .and_then(|items| items.get(index))
                .ok_or_else(|| SerializeError::MissingField(format!("[{index}]")))?
        };

        let member_type = member.type_ref.ok_or(SerializeError::UnknownType)?;
        let member_runtime = runtime_member(ctx.runtime_value, member.name.as_deref(), index);
        let member_bytes = serialize_value_inner(
            member_input,
            ctx.type_graph,
            member_type,
            member_runtime,
            &format!("{}{}", ctx.path, member_path_suffix(member, index)),
            ctx.offsets,
        )?;
        let offset = member_offset(member, ctx.runtime_value, index)
            .ok_or_else(|| SerializeError::MemberOffsetMissing(member_name(member, index)))?;
        let end = offset + member_bytes.len();
        if end > buffer.len() {
            return Err(SerializeError::SizeMismatch {
                expected: buffer.len(),
                actual: end,
            });
        }
        buffer[offset..end].copy_from_slice(&member_bytes);
        ctx.offsets.push(WriteOffset {
            path: format!("{}{}", ctx.path, member_path_suffix(member, index)),
            offset,
            size: member_bytes.len(),
        });
    }

    Ok(buffer)
}

fn serialize_union_value(
    ctx: &mut SerializeContext<'_>,
    byte_size: Option<u64>,
    members: &[StructureMember],
) -> Result<Vec<u8>, SerializeError> {
    let size = byte_size.ok_or(SerializeError::UnknownTypeSize(ctx.type_id))?;
    let mut buffer = vec![0u8; size as usize];
    let (member_idx, member_input) = match ctx.input {
        InputValue::Object(map) => {
            let (name, value) = map
                .iter()
                .next()
                .ok_or_else(|| SerializeError::UnsupportedInput("empty union".to_string()))?;
            let idx = members
                .iter()
                .position(|m| m.name.as_deref() == Some(name))
                .ok_or_else(|| SerializeError::MissingField(name.to_string()))?;
            (idx, value)
        }
        InputValue::Array(items) => {
            let value = items
                .first()
                .ok_or_else(|| SerializeError::UnsupportedInput("empty union".to_string()))?;
            (0, value)
        }
        _ => {
            return Err(SerializeError::UnexpectedInput(
                "union expects object with single field".to_string(),
            ));
        }
    };
    let member = &members[member_idx];
    let member_type = member.type_ref.ok_or(SerializeError::UnknownType)?;
    let member_runtime = runtime_member(ctx.runtime_value, member.name.as_deref(), member_idx);
    let member_bytes = serialize_value_inner(
        member_input,
        ctx.type_graph,
        member_type,
        member_runtime,
        &format!("{}{}", ctx.path, member_path_suffix(member, member_idx)),
        ctx.offsets,
    )?;
    let offset = member_offset(member, ctx.runtime_value, member_idx)
        .ok_or_else(|| SerializeError::MemberOffsetMissing(member_name(member, member_idx)))?;
    let end = offset + member_bytes.len();
    if end > buffer.len() {
        return Err(SerializeError::SizeMismatch {
            expected: buffer.len(),
            actual: end,
        });
    }
    buffer[offset..end].copy_from_slice(&member_bytes);
    ctx.offsets.push(WriteOffset {
        path: format!("{}{}", ctx.path, member_path_suffix(member, member_idx)),
        offset,
        size: member_bytes.len(),
    });
    Ok(buffer)
}

fn serialize_array_value(
    ctx: &mut SerializeContext<'_>,
    array: &ArrayType,
) -> Result<Vec<u8>, SerializeError> {
    let items = match ctx.input {
        InputValue::Array(items) => items,
        _ => {
            return Err(SerializeError::UnexpectedInput(
                "array expects list".to_string(),
            ));
        }
    };
    let element_type = array
        .element_type()
        .ok_or(SerializeError::ArrayElementTypeMissing)?;
    let mut buf = Vec::new();
    let mut element_size = None;
    for (idx, item) in items.iter().enumerate() {
        let runtime_item = runtime_array_item(ctx.runtime_value, idx);
        let bytes = serialize_value_inner(
            item,
            ctx.type_graph,
            element_type,
            runtime_item,
            &format!("{}[{idx}]", ctx.path),
            ctx.offsets,
        )?;
        let size = bytes.len();
        if let Some(existing) = element_size {
            if existing != size {
                return Err(SerializeError::SizeMismatch {
                    expected: existing,
                    actual: size,
                });
            }
        } else {
            element_size = Some(size);
        }
        buf.extend_from_slice(&bytes);
        ctx.offsets.push(WriteOffset {
            path: format!("{}[{idx}]", ctx.path),
            offset: idx * size,
            size,
        });
    }
    if let Some(expected_size) = array.byte_size_hint() {
        let expected_size = expected_size as usize;
        if expected_size != buf.len() {
            let element_size = element_size.unwrap_or(0);
            let expected_len = if element_size > 0 {
                expected_size / element_size
            } else {
                0
            };
            return Err(SerializeError::ArrayLengthMismatch {
                expected: expected_len,
                actual: items.len(),
            });
        }
    }
    Ok(buf)
}

fn serialize_c_enum_value(
    input: &InputValue,
    type_graph: &ComplexType,
    byte_size: Option<u64>,
    discr_type: Option<TypeId>,
    enumerators: &std::collections::HashMap<i64, String>,
) -> Result<Vec<u8>, SerializeError> {
    let name_or_value = match input {
        InputValue::Scalar(s) => s.clone(),
        InputValue::EnumVariant { name, .. } => name.clone(),
        _ => {
            return Err(SerializeError::UnexpectedInput(
                "enum expects scalar".to_string(),
            ));
        }
    };

    let discr_value = if let Ok(num) = name_or_value.parse::<i64>() {
        num
    } else {
        let (value, _) = enumerators
            .iter()
            .find(|(_, name)| *name == &name_or_value)
            .ok_or_else(|| SerializeError::EnumVariantNotFound(name_or_value.clone()))?;
        *value
    };

    if let Some(type_id) = discr_type {
        let input = InputValue::Scalar(discr_value.to_string());
        let mut offsets = Vec::new();
        let bytes = serialize_value_inner(&input, type_graph, type_id, None, "", &mut offsets)?;
        if let Some(byte_size) = byte_size {
            let expected = byte_size as usize;
            if bytes.len() != expected {
                return Err(SerializeError::SizeMismatch {
                    expected,
                    actual: bytes.len(),
                });
            }
        }
        return Ok(bytes);
    }

    let size = byte_size.unwrap_or(0) as usize;
    if size == 0 {
        return Err(SerializeError::EnumDiscriminantMissing);
    }
    int_to_bytes(discr_value as i128, size)
}

fn serialize_rust_enum_value(
    ctx: &mut SerializeContext<'_>,
    byte_size: Option<u64>,
    discr_member: Option<&StructureMember>,
    enumerators: &std::collections::HashMap<Option<i64>, StructureMember>,
) -> Result<Vec<u8>, SerializeError> {
    let size = byte_size.ok_or(SerializeError::UnknownTypeSize(ctx.type_id))?;
    let mut buffer = vec![0u8; size as usize];

    let (variant_name, payload) = match ctx.input {
        InputValue::EnumVariant { name, payload } => (name.clone(), payload.as_deref()),
        InputValue::Scalar(name) => (name.clone(), None),
        _ => {
            return Err(SerializeError::UnexpectedInput(
                "enum expects variant".to_string(),
            ));
        }
    };

    let (discr_value, variant_member) = enumerators
        .iter()
        .find(|(_, member)| member.name.as_deref() == Some(variant_name.as_str()))
        .map(|(discr, member)| (discr.unwrap_or_default(), member))
        .ok_or_else(|| SerializeError::EnumVariantNotFound(variant_name.clone()))?;

    if let Some(discr_member) = discr_member {
        let discr_type = discr_member
            .type_ref
            .ok_or(SerializeError::EnumDiscriminantMissing)?;
        let discr_bytes = serialize_value_inner(
            &InputValue::Scalar(discr_value.to_string()),
            ctx.type_graph,
            discr_type,
            None,
            ctx.path,
            ctx.offsets,
        )?;
        let offset = member_offset(discr_member, ctx.runtime_value, 0)
            .ok_or_else(|| SerializeError::MemberOffsetMissing("discriminant".to_string()))?;
        let end = offset + discr_bytes.len();
        if end > buffer.len() {
            return Err(SerializeError::SizeMismatch {
                expected: buffer.len(),
                actual: end,
            });
        }
        buffer[offset..end].copy_from_slice(&discr_bytes);
        ctx.offsets.push(WriteOffset {
            path: format!("{}.discriminant", ctx.path),
            offset,
            size: discr_bytes.len(),
        });
    }

    if let Some(variant_type) = variant_member.type_ref {
        let payload = payload.ok_or_else(|| SerializeError::MissingField(variant_name.clone()))?;
        let payload_bytes = serialize_value_inner(
            payload,
            ctx.type_graph,
            variant_type,
            runtime_member(ctx.runtime_value, variant_member.name.as_deref(), 0),
            &format!("{}.{}", ctx.path, variant_name),
            ctx.offsets,
        )?;
        let offset = member_offset(variant_member, ctx.runtime_value, 0)
            .ok_or_else(|| SerializeError::MemberOffsetMissing(format!("enum::{variant_name}")))?;
        let end = offset + payload_bytes.len();
        if end > buffer.len() {
            return Err(SerializeError::SizeMismatch {
                expected: buffer.len(),
                actual: end,
            });
        }
        buffer[offset..end].copy_from_slice(&payload_bytes);
        ctx.offsets.push(WriteOffset {
            path: format!("{}.{}", ctx.path, variant_name),
            offset,
            size: payload_bytes.len(),
        });
    }

    Ok(buffer)
}

fn member_path_suffix(member: &StructureMember, index: usize) -> String {
    member
        .name
        .as_deref()
        .map(|name| format!(".{name}"))
        .unwrap_or_else(|| format!("[{index}]"))
}

fn member_name(member: &StructureMember, index: usize) -> String {
    member
        .name
        .as_deref()
        .map(|name| name.to_string())
        .unwrap_or_else(|| format!("[{index}]"))
}

fn member_offset(
    member: &StructureMember,
    runtime_value: Option<&Value>,
    index: usize,
) -> Option<usize> {
    match member.in_struct_location.as_ref()? {
        MemberLocation::Offset(offset) => (*offset >= 0).then_some(*offset as usize),
        MemberLocation::Expr(_) => {
            let base = runtime_value?.in_memory_location()? as isize;
            let member_value = runtime_member(runtime_value, member.name.as_deref(), index)?;
            let member_addr = member_value.in_memory_location()? as isize;
            let offset = member_addr - base;
            (offset >= 0).then_some(offset as usize)
        }
    }
}

fn runtime_member<'a>(
    runtime_value: Option<&'a Value>,
    name: Option<&str>,
    index: usize,
) -> Option<&'a Value> {
    let Value::Struct(structure) = runtime_value? else {
        return None;
    };
    if let Some(name) = name {
        structure
            .members
            .iter()
            .find(|member| member.field_name.as_deref() == Some(name))
            .map(|member| &member.value)
    } else {
        structure.members.get(index).map(|member| &member.value)
    }
}

fn runtime_array_item(runtime_value: Option<&Value>, index: usize) -> Option<&Value> {
    let Value::Array(array) = runtime_value? else {
        return None;
    };
    array.items.as_ref()?.get(index).map(|item| &item.value)
}

fn int_to_bytes(value: i128, size: usize) -> Result<Vec<u8>, SerializeError> {
    let bytes = match size {
        1 => (value as i8).to_le_bytes().to_vec(),
        2 => (value as i16).to_le_bytes().to_vec(),
        4 => (value as i32).to_le_bytes().to_vec(),
        8 => (value as i64).to_le_bytes().to_vec(),
        16 => value.to_le_bytes().to_vec(),
        0 => Vec::new(),
        _ => {
            return Err(SerializeError::ScalarParse(format!(
                "unsupported int size {size}"
            )));
        }
    };
    Ok(bytes)
}

fn uint_to_bytes(value: u128, size: usize) -> Result<Vec<u8>, SerializeError> {
    let bytes = match size {
        1 => (value as u8).to_le_bytes().to_vec(),
        2 => (value as u16).to_le_bytes().to_vec(),
        4 => (value as u32).to_le_bytes().to_vec(),
        8 => (value as u64).to_le_bytes().to_vec(),
        16 => value.to_le_bytes().to_vec(),
        0 => Vec::new(),
        _ => {
            return Err(SerializeError::ScalarParse(format!(
                "unsupported uint size {size}"
            )));
        }
    };
    Ok(bytes)
}
