//! Translates the external code operations.

use revive_common::BIT_LENGTH_ETH_ADDRESS;

use crate::polkavm::context::Context;

/// Translates the `extcodesize` instruction if `address` is `Some`.
/// Otherwise, translates the `codesize` instruction.
pub fn size<'ctx>(
    context: &mut Context<'ctx>,
    address: Option<inkwell::values::IntValue<'ctx>>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>> {
    let address = match address {
        Some(address) => address,
        None => super::context::address(context)?.into_int_value(),
    };
    let address_pointer = context.build_address_argument_store(address)?;

    let code_size_value = context
        .build_runtime_call(
            revive_runtime_api::polkavm_imports::CODE_SIZE,
            &[address_pointer.to_int(context).into()],
        )
        .expect("the code_size syscall method should return a value")
        .into_int_value();

    Ok(context
        .builder()
        .build_int_z_extend(code_size_value, context.word_type(), "code_size")?
        .into())
}

/// Translates the `extcodehash` instruction.
pub fn hash<'ctx>(
    context: &mut Context<'ctx>,
    address: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>> {
    let address_type = context.integer_type(BIT_LENGTH_ETH_ADDRESS);
    let address_pointer = context.build_alloca_at_entry(address_type, "address_pointer");
    let address_truncated =
        context
            .builder()
            .build_int_truncate(address, address_type, "address_truncated")?;
    let address_swapped = context.build_byte_swap(address_truncated.into())?;
    context.build_store(address_pointer, address_swapped)?;

    let extcodehash_pointer =
        context.build_alloca_at_entry(context.word_type(), "extcodehash_pointer");

    context.build_runtime_call(
        revive_runtime_api::polkavm_imports::CODE_HASH,
        &[
            address_pointer.to_int(context).into(),
            extcodehash_pointer.to_int(context).into(),
        ],
    );

    context.build_byte_swap(context.build_load(extcodehash_pointer, "extcodehash_value")?)
}
