#include "../imports/stdlib.fc";

;; Built-in assembly functions
int keccak256(slice s) asm "1 PUSHINT HASHEXT_KECCAK256"; ;; Keccak-256 hash function
int keccak256_tuple(tuple t) asm "DUP TLEN EXPLODEVAR HASHEXT_KECCAK256";
int tlen(tuple t) asm "TLEN";

const MAX_BITS = 1016;

int keccak256_int(int hash) inline {
    slice hash_slice = begin_cell().store_uint(hash, 256).end_cell().begin_parse();
    return keccak256(hash_slice);
}

int keccak256_slice(slice s) inline {
    tuple slices = empty_tuple();
    int continue = true;

    while (continue) {
        if (~ s.slice_empty?()) {
            slice current_slice = s~load_bits(s.slice_bits());
            slices~tpush(current_slice);

            if (s.slice_refs_empty?()) {
                continue = false;
            } else {
                s = s~load_ref().begin_parse();
            }
        } else {
            continue = false;
        }
    }

    return keccak256_tuple(slices);
}

;; Splits a slice into chunks of MAX_BITS bits or less, in reverse order
(cell, slice) split_into_reverse_chunks(slice data, int size) {
    cell chunks = null();
    int total_bits_loaded = 0;
    builder current_chunk = begin_cell();
    while ((~ data.slice_empty?()) & (total_bits_loaded < size)) {
        int bits_to_load = min(min(data.slice_bits(), MAX_BITS - current_chunk.builder_bits()), size - total_bits_loaded);
        current_chunk = current_chunk.store_slice(data~load_bits(bits_to_load));
        total_bits_loaded += bits_to_load;
        if ((current_chunk.builder_bits() == MAX_BITS) | (size - total_bits_loaded == 0)) {
            slice current_chunk_slice = current_chunk.end_cell().begin_parse();
            if (cell_null?(chunks)) {
                chunks = begin_cell().store_slice(current_chunk_slice).end_cell();
            } else {
                chunks = begin_cell().store_slice(current_chunk_slice).store_ref(chunks).end_cell();
            }
            current_chunk = begin_cell();
        }
        if ((data.slice_bits() == 0) & (~ data.slice_refs_empty?())) {
            data = data~load_ref().begin_parse();
        }
    }
    return (chunks, data);
}

{-
This function reads a specified number of bits from the input slice and stores them in a cell structure,
handling data that may exceed the maximum cell capacity in FunC (1023 bits).
Optimized to build cells directly in forward order without double reversal.

Parameters:
   - in_msg_body: The input slice containing the data to be read
   - size: The number of bits to read from the input
Returns:
   - A tuple containing:
     1. A cell containing the read data, potentially spanning multiple cells if the size exceeds 1016 bits
     2. A slice containing the remaining unread data from the input

Note:
   - The function uses a maximum of 1016 bits per cell (instead of 1023) to ensure byte alignment
   - If the input data exceeds 1016 bits, it is split into multiple cells linked by references
   - Uses direct forward construction to avoid gas-inefficient double reversal
-}
(cell, slice) read_and_store_large_data(slice in_msg_body, int size) {
    ;; Collect chunks in order as we build them
    tuple chunk_list = empty_tuple();
    int total_bits_loaded = 0;
    builder current_builder = begin_cell();

    while ((~ in_msg_body.slice_empty?()) & (total_bits_loaded < size)) {
        int bits_to_load = min(min(in_msg_body.slice_bits(), MAX_BITS - current_builder.builder_bits()), size - total_bits_loaded);
        current_builder = current_builder.store_slice(in_msg_body~load_bits(bits_to_load));
        total_bits_loaded += bits_to_load;
        
        if ((current_builder.builder_bits() == MAX_BITS) | (size - total_bits_loaded == 0)) {
            cell current_chunk = current_builder.end_cell();
            chunk_list~tpush(current_chunk);
            current_builder = begin_cell();
        }
        
        if ((in_msg_body.slice_bits() == 0) & (~ in_msg_body.slice_refs_empty?())) {
            in_msg_body = in_msg_body~load_ref().begin_parse();
        }
    }
    
    ;; Build forward chain: first chunk → second chunk → third chunk etc
    cell result = null();
    int chunk_count = chunk_list.tlen();
    
    if (chunk_count > 0) {
        ;; Start from the last chunk (no references)
        result = chunk_list.at(chunk_count - 1);
        
        ;; Build forward by adding references from earlier chunks to later chunks
        int i = chunk_count - 2;
        while (i >= 0) {
            cell current_chunk = chunk_list.at(i);
            result = begin_cell().store_slice(current_chunk.begin_parse()).store_ref(result).end_cell();
            i -= 1;
        }
    }
    
    return (result, in_msg_body);
}


(int) pubkey_to_eth_address(int x1, int x2) {
    slice pubkey = begin_cell()
            .store_uint(x1, 256)
            .store_uint(x2, 256)
            .end_cell()
            .begin_parse();
    return keccak256(pubkey) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
}
