import typing
import typing_extensions

from .block import ExtraCurrencyCollection, GlobalVersion
from .tlb import TlbScheme, TlbError
from ..boc import Slice


class ConfigError(TlbError):
    pass


class ConfigParam0(TlbScheme):
    """
    _ config_addr:bits256 = ConfigParam 0;
    """
    def __init__(self, config_addr: bytes):
        self.config_addr = config_addr
        self.config_addr_hex = config_addr.hex()

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(cell_slice.load_bytes(32))

    # def __repr__(self):
    #     d = self.__dict__
    #     d.pop('config_addr')
    #     return f'{d}'


class ConfigParam1(TlbScheme):
    """
    _ elector_addr:bits256 = ConfigParam 1;
    """
    def __init__(self, elector_addr: bytes):
        self.elector_addr = elector_addr
        self.elector_addr_hex = elector_addr.hex()

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(cell_slice.load_bytes(32))


class ConfigParam2(TlbScheme):
    """
    _ minter_addr:bits256 = ConfigParam 2;  // ConfigParam 0 is used if absent
    """
    def __init__(self, minter_addr: bytes):
        self.minter_addr = minter_addr
        self.minter_addr_hex = minter_addr.hex()

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(cell_slice.load_bytes(32))


class ConfigParam3(TlbScheme):
    """
    _ fee_collector_addr:bits256 = ConfigParam 3;  // ConfigParam 1 is used if absent
    """
    def __init__(self, fee_collector_addr: bytes):
        self.fee_collector_addr = fee_collector_addr
        self.fee_collector_addr_hex = fee_collector_addr.hex()

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(cell_slice.load_bytes(32))


class ConfigParam4(TlbScheme):
    """
    _ dns_root_addr:bits256 = ConfigParam 4;  // root TON DNS resolver
    """
    def __init__(self, dns_root_addr: bytes):
        self.dns_root_addr = dns_root_addr
        self.dns_root_addr_hex = dns_root_addr.hex()

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(cell_slice.load_bytes(32))


class ConfigParam5(TlbScheme):
    """
    burning_config#01
    blackhole_addr:(Maybe bits256)
    fee_burn_nom:# fee_burn_denom:# { fee_burn_nom <= fee_burn_denom } { fee_burn_denom >= 1 } = BurningConfig;
    _ BurningConfig = ConfigParam 5;
    """
    def __init__(self,
                 blackhole_addr: typing.Optional[bytes],
                 fee_burn_nom: int,
                 fee_burn_denom: int,
                 ):
        self.blackhole_addr = blackhole_addr
        if blackhole_addr:
            self.blackhole_addr_hex = blackhole_addr.hex()
        self.fee_burn_nom = fee_burn_nom
        self.fee_burn_denom = fee_burn_denom

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag != b'\x01':
            raise ConfigError(f'BurningConfig deserialization error: unexpected tag {tag}')
        blackhole_addr = cell_slice.load_bytes(32) if cell_slice.load_bit() else None
        fee_burn_nom = cell_slice.load_uint(32)
        fee_burn_denom = cell_slice.load_uint(32)
        return cls(blackhole_addr, fee_burn_nom, fee_burn_denom)


class ConfigParam6(TlbScheme):
    """
    _ mint_new_price:Grams mint_add_price:Grams = ConfigParam 6;
    """
    def __init__(self, mint_new_price: int, mint_add_price: int):
        self.mint_new_price = mint_new_price
        self.mint_add_price = mint_add_price

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(cell_slice.load_coins(), cell_slice.load_coins())


class ConfigParam7(TlbScheme):
    """
    _ to_mint:ExtraCurrencyCollection = ConfigParam 7;
    """
    def __init__(self, to_mint: ExtraCurrencyCollection):
        self.to_mint = to_mint

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(ExtraCurrencyCollection.deserialize(cell_slice))


class ConfigParam8(GlobalVersion):
    """
    _ GlobalVersion = ConfigParam 8;  // all zero if absent
    """
    def __init__(self, **kwargs):  # TODO maybe change
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class ConfigParam9(TlbScheme):
    """
    _ mandatory_params:(Hashmap 32 True) = ConfigParam 9;
    """
    def __init__(self, mandatory_params: dict):
        self.mandatory_params = mandatory_params

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(cell_slice.load_hashmap(32, value_deserializer=lambda src: True))


class ConfigParam10(TlbScheme):
    """
    _ critical_params:(Hashmap 32 True) = ConfigParam 10;
    """
    def __init__(self, critical_params: dict):
        self.critical_params = critical_params

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(cell_slice.load_hashmap(32, value_deserializer=lambda src: True))


class ConfigProposalSetup(TlbScheme):
    """
    cfg_vote_cfg#36 min_tot_rounds:uint8 max_tot_rounds:uint8 min_wins:uint8 max_losses:uint8 min_store_sec:uint32 max_store_sec:uint32 bit_price:uint32 cell_price:uint32 = ConfigProposalSetup;
    """
    def __init__(self,
                 min_tot_rounds: int,
                 max_tot_rounds: int,
                 min_wins: int,
                 max_losses: int,
                 min_store_sec: int,
                 max_store_sec: int,
                 bit_price: int,
                 cell_price: int
                 ):

        self.min_tot_rounds = min_tot_rounds
        self.max_tot_rounds = max_tot_rounds
        self.min_wins = min_wins
        self.max_losses = max_losses
        self.min_store_sec = min_store_sec
        self.max_store_sec = max_store_sec
        self.bit_price = bit_price
        self.cell_price = cell_price

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag != b'\x36':
            raise ConfigError(f'ConfigProposalSetup deserialization error: unexpected tag {tag}')
        return cls(
            min_tot_rounds=cell_slice.load_uint(8),
            max_tot_rounds=cell_slice.load_uint(8),
            min_wins=cell_slice.load_uint(8),
            max_losses=cell_slice.load_uint(8),
            min_store_sec=cell_slice.load_uint(32),
            max_store_sec=cell_slice.load_uint(32),
            bit_price=cell_slice.load_uint(32),
            cell_price=cell_slice.load_uint(32)
        )


class ConfigVotingSetup(TlbScheme):
    """
    cfg_vote_setup#91 normal_params:^ConfigProposalSetup critical_params:^ConfigProposalSetup = ConfigVotingSetup;
    """
    def __init__(self, normal_params: ConfigProposalSetup, critical_params: ConfigProposalSetup):
        self.normal_params = normal_params
        self.critical_params = critical_params

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag != b'\x91':
            raise ConfigError(f'ConfigVotingSetup deserialization error: unexpected tag {tag}')
        return cls(
            normal_params=ConfigProposalSetup.deserialize(cell_slice.load_ref().begin_parse()),
            critical_params=ConfigProposalSetup.deserialize(cell_slice.load_ref().begin_parse())
        )


class ConfigParam11(ConfigVotingSetup):
    """
    _ ConfigVotingSetup = ConfigParam 11;
    """
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class WorkchainFormat(TlbScheme):
    """
    wfmt_basic#1 vm_version:int32 vm_mode:uint64 = WorkchainFormat 1;

    wfmt_ext#0 min_addr_len:(## 12) max_addr_len:(## 12) addr_len_step:(## 12)
    { min_addr_len >= 64 } { min_addr_len <= max_addr_len }
    { max_addr_len <= 1023 } { addr_len_step <= 1023 }
    workchain_type_id:(## 32) { workchain_type_id >= 1 }
    = WorkchainFormat 0;
    """

    def __init__(self,
                 type_: typing_extensions.Literal["wfmt_basic", "wfmt_ext"],
                 vm_version: typing.Optional[int] = None,
                 vm_mode: typing.Optional[int] = None,
                 min_addr_len: typing.Optional[int] = None,
                 max_addr_len: typing.Optional[int] = None,
                 addr_len_step: typing.Optional[int] = None,
                 workchain_type_id: typing.Optional[int] = None,
                 ):
        self.type_ = type_
        self.vm_version = vm_version
        self.vm_mode = vm_mode
        self.min_addr_len = min_addr_len
        self.max_addr_len = max_addr_len
        self.addr_len_step = addr_len_step
        self.workchain_type_id = workchain_type_id

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice, v: int = 0):
        tag = cell_slice.load_uint(4)
        if tag not in (0, 1):
            raise ConfigError(f'WorkchainFormat deserialization error: unexpected tag {tag}')
        if v:
            return cls(
                type_='wfmt_basic',
                vm_version=cell_slice.load_int(32),
                vm_mode=cell_slice.load_uint(64)
            )
        min_addr_len = cell_slice.load_uint(12)
        max_addr_len = cell_slice.load_uint(12)
        addr_len_step = cell_slice.load_uint(12)
        workchain_type_id = cell_slice.load_uint(32)
        assert min_addr_len >= 64
        assert min_addr_len <= max_addr_len
        assert max_addr_len <= 1023
        assert addr_len_step <= 1023
        assert workchain_type_id >= 1
        return cls(
            type_='wfmt_ext',
            min_addr_len=min_addr_len,
            max_addr_len=max_addr_len,
            addr_len_step=addr_len_step,
            workchain_type_id=workchain_type_id
        )


class WcSplitMergeTimings(TlbScheme):
    """
    wc_split_merge_timings#0
    split_merge_delay:uint32 split_merge_interval:uint32
    min_split_merge_interval:uint32 max_split_merge_delay:uint32
    = WcSplitMergeTimings;
    """

    def __init__(self,
                 split_merge_delay: int,
                 split_merge_interval: int,
                 min_split_merge_interval: int,
                 max_split_merge_delay: int,
                 ):
        self.split_merge_delay = split_merge_delay
        self.split_merge_interval = split_merge_interval
        self.min_split_merge_interval = min_split_merge_interval
        self.max_split_merge_delay = max_split_merge_delay

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_uint(4)
        if tag != 0:
            raise ConfigError(f'WorkchainFormat deserialization error: unexpected tag {tag}')
        return cls(
            split_merge_delay=cell_slice.load_uint(32),
            split_merge_interval=cell_slice.load_uint(32),
            min_split_merge_interval=cell_slice.load_uint(32),
            max_split_merge_delay=cell_slice.load_uint(32)
        )


class WorkchainDescr(TlbScheme):
    """
    workchain#a6 enabled_since:uint32 actual_min_split:(## 8)
    min_split:(## 8) max_split:(## 8) { actual_min_split <= min_split }
    basic:(## 1) active:Bool accept_msgs:Bool flags:(## 13) { flags = 0 }
    zerostate_root_hash:bits256 zerostate_file_hash:bits256
    version:uint32 format:(WorkchainFormat basic)
    = WorkchainDescr;

    workchain_v2#a7 enabled_since:uint32 actual_min_split:(## 8)
    min_split:(## 8) max_split:(## 8) { actual_min_split <= min_split }
    basic:(## 1) active:Bool accept_msgs:Bool flags:(## 13) { flags = 0 }
    zerostate_root_hash:bits256 zerostate_file_hash:bits256
    version:uint32 format:(WorkchainFormat basic)
    split_merge_timings:WcSplitMergeTimings
    persistent_state_split_depth:(## 8) { persistent_state_split_depth <= 63 }
    = WorkchainDescr;
    """

    def __init__(self,
                 type_: typing_extensions.Literal["workchain", "workchain_v2"],
                 enabled_since: int,
                 actual_min_split: int,
                 min_split: int,
                 max_split: int,
                 basic: int,
                 active: bool,
                 accept_msgs: bool,
                 flags: int,
                 zerostate_root_hash: bytes,
                 zerostate_file_hash: bytes,
                 version: int,
                 format: WorkchainFormat,
                 split_merge_timings: typing.Optional[WcSplitMergeTimings] = None,
                 persistent_state_split_depth: typing.Optional[int] = None,
                 ):
        self.type_ = type_
        self.enabled_since = enabled_since
        self.actual_min_split = actual_min_split
        self.min_split = min_split
        self.max_split = max_split
        self.basic = basic
        self.active = active
        self.accept_msgs = accept_msgs
        self.flags = flags
        self.zerostate_root_hash = zerostate_root_hash
        self.zerostate_file_hash = zerostate_file_hash
        self.version = version
        self.format = format
        self.split_merge_timings = split_merge_timings
        self.persistent_state_split_depth = persistent_state_split_depth

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag not in (b'\xa6', b'\xa7'):
            raise ConfigError(f'WorkchainDescr deserialization error: unexpected tag {tag}')
        enabled_since = cell_slice.load_uint(32)
        actual_min_split = cell_slice.load_uint(8)
        min_split = cell_slice.load_uint(8)
        max_split = cell_slice.load_uint(8)
        assert actual_min_split <= min_split
        basic = cell_slice.load_bit()
        active = cell_slice.load_bool()
        accept_msgs = cell_slice.load_bool()
        flags = cell_slice.load_uint(13)
        assert flags == 0
        zerostate_root_hash = cell_slice.load_bytes(32)
        zerostate_file_hash = cell_slice.load_bytes(32)
        version = cell_slice.load_uint(32)
        format = WorkchainFormat.deserialize(cell_slice, basic)
        type_ = 'workchain' if tag == b'\xa6' else 'workchain_v2'
        split_merge_timings = None
        persistent_state_split_depth = None
        if type_ == 'workchain_v2':
            split_merge_timings = WcSplitMergeTimings.deserialize(cell_slice)
            persistent_state_split_depth = cell_slice.load_uint(8)
            assert persistent_state_split_depth <= 63
        return cls(
            type_=type_,
            enabled_since=enabled_since,
            actual_min_split=actual_min_split,
            min_split=min_split,
            max_split=max_split,
            basic=basic,
            active=active,
            accept_msgs=accept_msgs,
            flags=flags,
            zerostate_root_hash=zerostate_root_hash,
            zerostate_file_hash=zerostate_file_hash,
            version=version,
            format=format,
            split_merge_timings=split_merge_timings,
            persistent_state_split_depth=persistent_state_split_depth
        )


class ConfigParam12(TlbScheme):
    """
    _ workchains:(HashmapE 32 WorkchainDescr) = ConfigParam 12;
    """
    def __init__(self, workchains: typing.Dict[int, WorkchainDescr]):
        self.workchains = workchains

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(
            workchains=cell_slice.load_dict(32, value_deserializer=WorkchainDescr.deserialize)
        )


class ComplaintPricing(TlbScheme):
    """
    complaint_prices#1a deposit:Grams bit_price:Grams cell_price:Grams = ComplaintPricing;
    """
    def __init__(self,
                 deposit: int,
                 bit_price: int,
                 cell_price: int,
                 ):
        self.deposit = deposit
        self.bit_price = bit_price
        self.cell_price = cell_price

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag != b'\x1a':
            raise ConfigError(f'ComplaintPricing deserialization error: unexpected prefix tag {tag}')
        return cls(
            deposit=cell_slice.load_coins(),
            bit_price=cell_slice.load_coins(),
            cell_price=cell_slice.load_coins()
        )


class ConfigParam13(ComplaintPricing):
    """
    _ ComplaintPricing = ConfigParam 13;
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class BlockCreateFees(TlbScheme):
    """
    block_grams_created#6b masterchain_block_fee:Grams basechain_block_fee:Grams
    = BlockCreateFees;
    """
    def __init__(self,
                 masterchain_block_fee: int,
                 basechain_block_fee: int,
                 ):
        self.masterchain_block_fee = masterchain_block_fee
        self.basechain_block_fee = basechain_block_fee

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag != b'\x6b':
            raise ConfigError(f'BlockCreateFees deserialization error: unexpected prefix tag {tag}')
        return cls(
            masterchain_block_fee=cell_slice.load_coins(),
            basechain_block_fee=cell_slice.load_coins(),
        )


class ConfigParam14(BlockCreateFees):
    """
    _ BlockCreateFees = ConfigParam 14;
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class ConfigParam15(TlbScheme):
    """
    _ validators_elected_for:uint32 elections_start_before:uint32
      elections_end_before:uint32 stake_held_for:uint32
      = ConfigParam 15;
    """
    def __init__(self,
                 validators_elected_for: int,
                 elections_start_before: int,
                 elections_end_before: int,
                 stake_held_for: int,
                 ):
        self.validators_elected_for = validators_elected_for
        self.elections_start_before = elections_start_before
        self.elections_end_before = elections_end_before
        self.stake_held_for = stake_held_for

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(
            validators_elected_for=cell_slice.load_uint(32),
            elections_start_before=cell_slice.load_uint(32),
            elections_end_before=cell_slice.load_uint(32),
            stake_held_for=cell_slice.load_uint(32)
        )


class ConfigParam16(TlbScheme):
    """
    _ max_validators:(## 16) max_main_validators:(## 16) min_validators:(## 16)
      { max_validators >= max_main_validators }
      { max_main_validators >= min_validators }
      { min_validators >= 1 }
      = ConfigParam 16;
    """
    def __init__(self,
                 max_validators: int,
                 max_main_validators: int,
                 min_validators: int,
                 ):
        self.max_validators = max_validators
        self.max_main_validators = max_main_validators
        self.min_validators = min_validators

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        max_validators = cell_slice.load_uint(16)
        max_main_validators = cell_slice.load_uint(16)
        min_validators = cell_slice.load_uint(16)
        assert max_validators >= max_main_validators
        assert max_main_validators >= min_validators
        assert min_validators >= 1
        return cls(
            max_validators=max_validators,
            max_main_validators=max_main_validators,
            min_validators=min_validators
        )


class ConfigParam17(TlbScheme):
    """
    _ min_stake:Grams max_stake:Grams min_total_stake:Grams max_stake_factor:uint32 = ConfigParam 17;
    """
    def __init__(self,
                 min_stake: int,
                 max_stake: int,
                 min_total_stake: int,
                 max_stake_factor: int
                 ):
        self.min_stake = min_stake
        self.max_stake = max_stake
        self.min_total_stake = min_total_stake
        self.max_stake_factor = max_stake_factor

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(
            min_stake=cell_slice.load_coins(),
            max_stake=cell_slice.load_coins(),
            min_total_stake=cell_slice.load_coins(),
            max_stake_factor=cell_slice.load_uint(32)
        )


class StoragePrices(TlbScheme):
    """
    _#cc utime_since:uint32 bit_price_ps:uint64 cell_price_ps:uint64
    mc_bit_price_ps:uint64 mc_cell_price_ps:uint64 = StoragePrices;
    """
    def __init__(self,
                 utime_since: int,
                 bit_price_ps: int,
                 cell_price_ps: int,
                 mc_bit_price_ps: int,
                 mc_cell_price_ps: int,
                 ):
        self.utime_since = utime_since
        self.bit_price_ps = bit_price_ps
        self.cell_price_ps = cell_price_ps
        self.mc_bit_price_ps = mc_bit_price_ps
        self.mc_cell_price_ps = mc_cell_price_ps

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag != b'\xcc':
            raise ConfigError(f'StoragePrices deserialization error: unexpected prefix tag: {tag}')
        return cls(
            utime_since=cell_slice.load_uint(32),
            bit_price_ps=cell_slice.load_uint(64),
            cell_price_ps=cell_slice.load_uint(64),
            mc_bit_price_ps=cell_slice.load_uint(64),
            mc_cell_price_ps=cell_slice.load_uint(64)
        )


class ConfigParam18(TlbScheme):
    """
    _ (Hashmap 32 StoragePrices) = ConfigParam 18;
    """

    @classmethod
    def serialize(cls, *args):
        pass

    @classmethod
    def deserialize(cls, cell_slice: Slice) -> typing.Dict[int, StoragePrices]:
        return cell_slice.load_hashmap(32, value_deserializer=StoragePrices.deserialize)


class GasLimitsPrices(TlbScheme):
    """
    gas_prices#dd gas_price:uint64 gas_limit:uint64 gas_credit:uint64
    block_gas_limit:uint64 freeze_due_limit:uint64 delete_due_limit:uint64
    = GasLimitsPrices;

    gas_prices_ext#de gas_price:uint64 gas_limit:uint64 special_gas_limit:uint64 gas_credit:uint64
    block_gas_limit:uint64 freeze_due_limit:uint64 delete_due_limit:uint64
    = GasLimitsPrices;

    gas_flat_pfx#d1 flat_gas_limit:uint64 flat_gas_price:uint64 other:GasLimitsPrices
    = GasLimitsPrices;
    """
    def __init__(self,
                 type_: typing_extensions.Literal["gas_prices", "gas_prices_ext", "gas_flat_pfx"],
                 gas_price: typing.Optional[int] = None,
                 gas_limit: typing.Optional[int] = None,
                 gas_credit: typing.Optional[int] = None,
                 block_gas_limit: typing.Optional[int] = None,
                 freeze_due_limit: typing.Optional[int] = None,
                 delete_due_limit: typing.Optional[int] = None,
                 special_gas_limit: typing.Optional[int] = None,
                 flat_gas_limit: typing.Optional[int] = None,
                 flat_gas_price: typing.Optional[int] = None,
                 other: typing.Optional["GasLimitsPrices"] = None
                 ):
        self.type_ = type_
        self.gas_price = gas_price
        self.gas_limit = gas_limit
        self.gas_credit = gas_credit
        self.block_gas_limit = block_gas_limit
        self.freeze_due_limit = freeze_due_limit
        self.delete_due_limit = delete_due_limit
        self.special_gas_limit = special_gas_limit
        self.flat_gas_limit = flat_gas_limit
        self.flat_gas_price = flat_gas_price
        self.other = other

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag in (b'\xdd', b'\xde'):
            gas_price = cell_slice.load_uint(64)
            gas_limit = cell_slice.load_uint(64)
            type_ = 'gas_prices'
            special_gas_limit = None
            if tag == b'\xde':
                type_ = 'gas_prices_ext'
                special_gas_limit = cell_slice.load_uint(64)
            gas_credit = cell_slice.load_uint(64)
            block_gas_limit = cell_slice.load_uint(64)
            freeze_due_limit = cell_slice.load_uint(64)
            delete_due_limit = cell_slice.load_uint(64)
            return cls(
                type_=type_,
                gas_price=gas_price,
                gas_limit=gas_limit,
                gas_credit=gas_credit,
                special_gas_limit=special_gas_limit,
                block_gas_limit=block_gas_limit,
                freeze_due_limit=freeze_due_limit,
                delete_due_limit=delete_due_limit
            )
        elif tag == b'\xd1':
            return cls(
                type_='gas_flat_pfx',
                flat_gas_limit=cell_slice.load_uint(64),
                flat_gas_price=cell_slice.load_uint(64),
                other=cls.deserialize(cell_slice)
            )
        raise ConfigError(f'GasLimitsPrices deserialization error: unknown prefix tag: {tag}')


class ConfigParam20(GasLimitsPrices):
    """
    config_mc_gas_prices#_ GasLimitsPrices = ConfigParam 20;
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class ConfigParam21(GasLimitsPrices):
    """
    config_gas_prices#_ GasLimitsPrices = ConfigParam 21;
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class ParamLimits(TlbScheme):
    """
    param_limits#c3 underload:# soft_limit:# { underload <= soft_limit }
    hard_limit:# { soft_limit <= hard_limit } = ParamLimits;
    """
    def __init__(self,
                 underload: int,
                 soft_limit: int,
                 hard_limit: int,
                 ):
        self.underload = underload
        self.soft_limit = soft_limit
        self.hard_limit = hard_limit

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag != b'\xc3':
            raise ConfigError(f'ParamLimits deserialization error: unexpected tag {tag}')
        underload = cell_slice.load_uint(32)
        soft_limit = cell_slice.load_uint(32)
        assert underload <= soft_limit
        hard_limit = cell_slice.load_uint(32)
        assert soft_limit <= hard_limit
        return cls(
            underload=underload,
            soft_limit=soft_limit,
            hard_limit=hard_limit
        )


class BlockLimits(TlbScheme):
    """
    block_limits#5d bytes:ParamLimits gas:ParamLimits lt_delta:ParamLimits
    = BlockLimits;
    """
    def __init__(self,
                 bytes: ParamLimits,
                 gas: ParamLimits,
                 lt_delta: ParamLimits):
        self.bytes = bytes
        self.gas = gas
        self.lt_delta = lt_delta

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag != b'\x5d':
            raise ConfigError(f'BlockLimits deserialization error: unexpected tag {tag}')
        return cls(
            bytes=ParamLimits.deserialize(cell_slice),
            gas=ParamLimits.deserialize(cell_slice),
            lt_delta=ParamLimits.deserialize(cell_slice),
        )


class ConfigParam22(BlockLimits):
    """
    config_mc_block_limits#_ BlockLimits = ConfigParam 22;
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class ConfigParam23(BlockLimits):
    """
    config_block_limits#_ BlockLimits = ConfigParam 23;
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class MsgForwardPrices(TlbScheme):
    """
    msg_forward_prices#ea lump_price:uint64 bit_price:uint64 cell_price:uint64
    ihr_price_factor:uint32 first_frac:uint16 next_frac:uint16 = MsgForwardPrices;
    """
    def __init__(self,
                 lump_price: int,
                 bit_price: int,
                 cell_price: int,
                 ihr_price_factor: int,
                 first_frac: int,
                 next_frac: int
                 ):
        self.lump_price = lump_price
        self.bit_price = bit_price
        self.cell_price = cell_price
        self.ihr_price_factor = ihr_price_factor
        self.first_frac = first_frac
        self.next_frac = next_frac

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag != b'\xea':
            raise ConfigError(f'ParamLimits deserialization error: unexpected tag {tag}')
        return cls(
            lump_price=cell_slice.load_uint(64),
            bit_price=cell_slice.load_uint(64),
            cell_price=cell_slice.load_uint(64),
            ihr_price_factor=cell_slice.load_uint(32),
            first_frac=cell_slice.load_uint(16),
            next_frac=cell_slice.load_uint(16),
        )


class ConfigParam24(MsgForwardPrices):
    """
    // used for messages to/from masterchain
    config_mc_fwd_prices#_ MsgForwardPrices = ConfigParam 24;
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class ConfigParam25(MsgForwardPrices):
    """
    // used for all other messages
    config_fwd_prices#_ MsgForwardPrices = ConfigParam 25;
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class CatchainConfig(TlbScheme):
    """
    catchain_config#c1 mc_catchain_lifetime:uint32 shard_catchain_lifetime:uint32
    shard_validators_lifetime:uint32 shard_validators_num:uint32 = CatchainConfig;

    catchain_config_new#c2 flags:(## 7) { flags = 0 } shuffle_mc_validators:Bool
    mc_catchain_lifetime:uint32 shard_catchain_lifetime:uint32
    shard_validators_lifetime:uint32 shard_validators_num:uint32 = CatchainConfig;
    """

    def __init__(self, type_: typing_extensions.Literal["catchain_config", "catchain_config_new"],
                 mc_catchain_lifetime: int,
                 shard_catchain_lifetime: int,
                 shard_validators_lifetime: int,
                 shard_validators_num: int,
                 shuffle_mc_validators: typing.Optional[bool] = None,
                 ):
        self.type_ = type_
        self.mc_catchain_lifetime = mc_catchain_lifetime
        self.shard_catchain_lifetime = shard_catchain_lifetime
        self.shard_validators_lifetime = shard_validators_lifetime
        self.shard_validators_num = shard_validators_num
        self.shuffle_mc_validators = shuffle_mc_validators

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag == b'\xc1':
            return cls(
                type_='catchain_config',
                mc_catchain_lifetime=cell_slice.load_uint(32),
                shard_catchain_lifetime=cell_slice.load_uint(32),
                shard_validators_lifetime=cell_slice.load_uint(32),
                shard_validators_num=cell_slice.load_uint(32)
            )
        elif tag == b'\xc2':
            flags = cell_slice.load_uint(7)
            assert flags == 0
            return cls(
                type_='catchain_config_new',
                shuffle_mc_validators=cell_slice.load_bool(),
                mc_catchain_lifetime=cell_slice.load_uint(32),
                shard_catchain_lifetime=cell_slice.load_uint(32),
                shard_validators_lifetime=cell_slice.load_uint(32),
                shard_validators_num=cell_slice.load_uint(32)
            )
        else:
            raise ConfigError(f'CatchainConfig deserialization error: unexpected tag {tag}')


class ConfigParam28(CatchainConfig):
    """
    _ CatchainConfig = ConfigParam 28;
    """

    def __init__(self, **kwargs):  # TODO maybe change
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class ConsensusConfig(TlbScheme):
    """
    consensus_config#d6 round_candidates:# { round_candidates >= 1 }
    next_candidate_delay_ms:uint32 consensus_timeout_ms:uint32
    fast_attempts:uint32 attempt_duration:uint32 catchain_max_deps:uint32
    max_block_bytes:uint32 max_collated_bytes:uint32 = ConsensusConfig;

    consensus_config_new#d7 flags:(## 7) { flags = 0 } new_catchain_ids:Bool
    round_candidates:(## 8) { round_candidates >= 1 }
    next_candidate_delay_ms:uint32 consensus_timeout_ms:uint32
    fast_attempts:uint32 attempt_duration:uint32 catchain_max_deps:uint32
    max_block_bytes:uint32 max_collated_bytes:uint32 = ConsensusConfig;

    consensus_config_v3#d8 flags:(## 7) { flags = 0 } new_catchain_ids:Bool
    round_candidates:(## 8) { round_candidates >= 1 }
    next_candidate_delay_ms:uint32 consensus_timeout_ms:uint32
    fast_attempts:uint32 attempt_duration:uint32 catchain_max_deps:uint32
    max_block_bytes:uint32 max_collated_bytes:uint32
    proto_version:uint16 = ConsensusConfig;

    consensus_config_v4#d9 flags:(## 7) { flags = 0 } new_catchain_ids:Bool
    round_candidates:(## 8) { round_candidates >= 1 }
    next_candidate_delay_ms:uint32 consensus_timeout_ms:uint32
    fast_attempts:uint32 attempt_duration:uint32 catchain_max_deps:uint32
    max_block_bytes:uint32 max_collated_bytes:uint32
    proto_version:uint16 catchain_max_blocks_coeff:uint32 = ConsensusConfig;
    """

    def __init__(self, type_: typing_extensions.Literal["consensus_config", "consensus_config_new", "consensus_config_v3", "consensus_config_v4"],
                 round_candidates: typing.Optional[int] = None,
                 next_candidate_delay_ms: typing.Optional[int] = None,
                 consensus_timeout_ms: typing.Optional[int] = None,
                 fast_attempts: typing.Optional[int] = None,
                 attempt_duration: typing.Optional[int] = None,
                 catchain_max_deps: typing.Optional[int] = None,
                 max_block_bytes: typing.Optional[int] = None,
                 max_collated_bytes: typing.Optional[int] = None,
                 flags: typing.Optional[int] = None,
                 new_catchain_ids: typing.Optional[int] = None,
                 proto_version: typing.Optional[int] = None,
                 catchain_max_blocks_coeff: typing.Optional[int] = None,
                 ):
        self.type_ = type_
        self.round_candidates = round_candidates
        self.next_candidate_delay_ms = next_candidate_delay_ms
        self.consensus_timeout_ms = consensus_timeout_ms
        self.fast_attempts = fast_attempts
        self.attempt_duration = attempt_duration
        self.catchain_max_deps = catchain_max_deps
        self.max_block_bytes = max_block_bytes
        self.max_collated_bytes = max_collated_bytes
        self.flags = flags
        self.new_catchain_ids = new_catchain_ids
        self.proto_version = proto_version
        self.catchain_max_blocks_coeff = catchain_max_blocks_coeff

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        types = {
            b'\xd6': 'consensus_config',
            b'\xd7': 'consensus_config_new',
            b'\xd8': 'consensus_config_v3',
            b'\xd9': 'consensus_config_v4',
        }
        if tag not in types:
            raise ConfigError(f'ConsensusConfig deserialization error: unexpected tag {tag}')
        type_ = types.get(tag)
        flags = None
        new_catchain_ids = None
        if type_ != 'consensus_config':
            flags = cell_slice.load_uint(7)
            assert flags == 0
            new_catchain_ids = cell_slice.load_bool()
            round_candidates = cell_slice.load_uint(8)
        else:
            round_candidates = cell_slice.load_uint(32)
        assert round_candidates >= 1
        next_candidate_delay_ms = cell_slice.load_uint(32)
        consensus_timeout_ms = cell_slice.load_uint(32)
        fast_attempts = cell_slice.load_uint(32)
        attempt_duration = cell_slice.load_uint(32)
        catchain_max_deps = cell_slice.load_uint(32)
        max_block_bytes = cell_slice.load_uint(32)
        max_collated_bytes = cell_slice.load_uint(32)
        proto_version = None
        catchain_max_blocks_coeff = None
        if type_ in ('consensus_config_v3', 'consensus_config_v4'):
            proto_version = cell_slice.load_uint(16)
        if type_ == 'consensus_config_v4':
            catchain_max_blocks_coeff = cell_slice.load_uint(32)
        return cls(
            type_=type_,
            flags=flags,
            new_catchain_ids=new_catchain_ids,
            round_candidates=round_candidates,
            next_candidate_delay_ms=next_candidate_delay_ms,
            consensus_timeout_ms=consensus_timeout_ms,
            fast_attempts=fast_attempts,
            attempt_duration=attempt_duration,
            catchain_max_deps=catchain_max_deps,
            max_block_bytes=max_block_bytes,
            max_collated_bytes=max_collated_bytes,
            proto_version=proto_version,
            catchain_max_blocks_coeff=catchain_max_blocks_coeff,
        )


class ConfigParam29(ConsensusConfig):
    """
    _ ConsensusConfig = ConfigParam 29;
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class ConfigParam31(TlbScheme):
    """
    _ fundamental_smc_addr:(HashmapE 256 True) = ConfigParam 31;
    """

    def __init__(self, fundamental_smc_addr: dict):
        self.fundamental_smc_addr = fundamental_smc_addr

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(fundamental_smc_addr=cell_slice.load_dict(256, value_deserializer=lambda src: True))


class SigPubKey(TlbScheme):
    """
    ed25519_pubkey#8e81278a pubkey:bits256 = SigPubKey;  // 288 bits
    """
    def __init__(self, pubkey: bytes):
        self.pubkey = pubkey

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(4)
        if tag != b"\x8e\x81'\x8a":
            raise ConfigError(f'SigPubKey deserialization error: unexpected tag {tag}')
        return cls(cell_slice.load_bytes(32))


class ValidatorDescr(TlbScheme):
    """
    validator#53 public_key:SigPubKey weight:uint64 = ValidatorDescr;
    validator_addr#73 public_key:SigPubKey weight:uint64 adnl_addr:bits256 = ValidatorDescr;
    """
    def __init__(self,
                 type_: str,
                 public_key: SigPubKey,
                 weight: int,
                 adnl_addr: typing.Optional[bytes] = None
                 ):
        self.type_ = type_
        self.public_key = public_key
        self.weight = weight
        self.adnl_addr = adnl_addr

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag not in (b'\x53', b'\x73'):
            raise ConfigError(f'ValidatorDescr deserialization error: unexpected tag {tag}')
        public_key = SigPubKey.deserialize(cell_slice)
        weight = cell_slice.load_uint(64)
        adnl_addr = None
        type_ = 'validator'
        if tag == b'\x73':
            type_ = 'validator_addr'
            adnl_addr = cell_slice.load_bytes(32)
        return cls(
            type_=type_,
            public_key=public_key,
            weight=weight,
            adnl_addr=adnl_addr
        )


class ValidatorSet(TlbScheme):
    """
    validators#11 utime_since:uint32 utime_until:uint32
    total:(## 16) main:(## 16) { main <= total } { main >= 1 }
    list:(Hashmap 16 ValidatorDescr) = ValidatorSet;

    validators_ext#12 utime_since:uint32 utime_until:uint32
    total:(## 16) main:(## 16) { main <= total } { main >= 1 }
    total_weight:uint64 list:(HashmapE 16 ValidatorDescr) = ValidatorSet;
    """

    def __init__(self,
                 type_: str,
                 utime_since: int,
                 utime_until: int,
                 total: int,
                 main: int,
                 total_weight: typing.Optional[int],
                 list: typing.Dict[int, "ValidatorDescr"]
                 ):

        self.type_ = type_
        self.utime_since = utime_since
        self.utime_until = utime_until
        self.total = total
        self.main = main
        self.total_weight = total_weight
        self.list = list

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag not in (b'\x11', b'\x12'):
            raise ConfigError(f'ValidatorSet deserialization error: unknown prefix tag: {tag}')
        utime_since = cell_slice.load_uint(32)
        utime_until = cell_slice.load_uint(32)
        total = cell_slice.load_uint(16)
        main = cell_slice.load_uint(16)

        if not main <= total:
            raise ConfigError(f'expected main <= total, got: main={main}, total={total}')
        if not main >= 1:
            raise ConfigError(f'expected main >= 1, got: main={main}')
        total_weight = None
        type_ = 'validators'
        if tag == b'\x12':
            type_ = 'validators_ext'
            total_weight = cell_slice.load_uint(64)
        list = cell_slice.load_dict(16, value_deserializer=ValidatorDescr.deserialize)

        return cls(
            type_=type_,
            utime_since=utime_since,
            utime_until=utime_until,
            total=total,
            main=main,
            total_weight=total_weight,
            list=list
        )


class ConfigParam32(TlbScheme):
    """
    _ prev_validators:ValidatorSet = ConfigParam 32;
    """

    def __init__(self, prev_validators: "ValidatorSet"):
        self.prev_validators = prev_validators

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(prev_validators=ValidatorSet.deserialize(cell_slice))


class ConfigParam33(TlbScheme):
    """
    _ prev_temp_validators:ValidatorSet = ConfigParam 33;
    """

    def __init__(self, prev_temp_validators: "ValidatorSet"):
        self.prev_temp_validators = prev_temp_validators

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(prev_temp_validators=ValidatorSet.deserialize(cell_slice))


class ConfigParam34(TlbScheme):
    """
    _ cur_validators:ValidatorSet = ConfigParam 34;
    """

    def __init__(self, cur_validators: "ValidatorSet"):
        self.cur_validators = cur_validators

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(cur_validators=ValidatorSet.deserialize(cell_slice))

class ConfigParam35(TlbScheme):
    """
    _ cur_temp_validators:ValidatorSet = ConfigParam 35;
    """

    def __init__(self, cur_temp_validators: "ValidatorSet"):
        self.cur_temp_validators = cur_temp_validators

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(cur_temp_validators=ValidatorSet.deserialize(cell_slice))


class ConfigParam36(TlbScheme):
    """
    _ next_validators:ValidatorSet = ConfigParam 36;
    """

    def __init__(self, next_validators: "ValidatorSet"):
        self.next_validators = next_validators

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(next_validators=ValidatorSet.deserialize(cell_slice))


class ConfigParam37(TlbScheme):
    """
    _ next_temp_validators:ValidatorSet = ConfigParam 37;
    """

    def __init__(self, next_temp_validators: "ValidatorSet"):
        self.next_temp_validators = next_temp_validators

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(next_temp_validators=ValidatorSet.deserialize(cell_slice))


class SuspendedAddressList(TlbScheme):
    """
    suspended_address_list#00 addresses:(HashmapE 288 Unit) suspended_until:uint32 = SuspendedAddressList;
    """
    def __init__(self,
                 addresses: dict,
                 suspended_until: int
                 ):
        self.addresses = addresses
        self.suspended_until = suspended_until

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag != b'\x00':
            raise ConfigError(f'SuspendedAddressList deserialization error: unexpected prefix tag {tag}')
        return cls(
            addresses=cell_slice.load_dict(288, value_deserializer=lambda src: None),
            suspended_until=cell_slice.load_uint(32)
        )


class ConfigParam44(SuspendedAddressList):
    """
    _ SuspendedAddressList = ConfigParam 44;
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class OracleBridgeParams(TlbScheme):
    """
    oracle_bridge_params#_ bridge_address:bits256 oracle_mutlisig_address:bits256 oracles:(HashmapE 256 uint256) external_chain_address:bits256 = OracleBridgeParams;
    """
    def __init__(self,
                 bridge_address: bytes,
                 oracle_mutlisig_address: bytes,
                 oracles: dict,
                 external_chain_address: bytes
                 ):
        self.bridge_address = bridge_address
        self.bridge_address_hex = bridge_address.hex()
        self.oracle_mutlisig_address = oracle_mutlisig_address
        self.oracle_mutlisig_address_hex = oracle_mutlisig_address.hex()
        self.oracles = oracles
        self.external_chain_address_hex = external_chain_address.hex()

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(
            bridge_address=cell_slice.load_bytes(32),
            oracle_mutlisig_address=cell_slice.load_bytes(32),
            oracles=cell_slice.load_dict(256, value_deserializer=lambda src: src.load_uint(256)),
            external_chain_address=cell_slice.load_bytes(32)
        )


class ConfigParam71(OracleBridgeParams):
    """
    _ OracleBridgeParams = ConfigParam 71; // Ethereum bridge
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class ConfigParam72(OracleBridgeParams):
    """
    _ OracleBridgeParams = ConfigParam 72; // Binance Smart Chain bridge
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class ConfigParam73(OracleBridgeParams):
    """
    _ OracleBridgeParams = ConfigParam 73; // Polygon bridge
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class JettonBridgePrices(TlbScheme):
    """
    // Note that chains in which bridge, minter and jetton-wallet operate are fixated
    jetton_bridge_prices#_ bridge_burn_fee:Coins bridge_mint_fee:Coins
                           wallet_min_tons_for_storage:Coins
                           wallet_gas_consumption:Coins
                           minter_min_tons_for_storage:Coins
                           discover_gas_consumption:Coins = JettonBridgePrices;
    """
    def __init__(self,
                 bridge_burn_fee: int,
                 bridge_mint_fee: int,
                 wallet_min_tons_for_storage: int,
                 wallet_gas_consumption: int,
                 minter_min_tons_for_storage: int,
                 discover_gas_consumption: int,
                 ):
        self.bridge_burn_fee = bridge_burn_fee
        self.bridge_mint_fee = bridge_mint_fee
        self.wallet_min_tons_for_storage = wallet_min_tons_for_storage
        self.wallet_gas_consumption = wallet_gas_consumption
        self.minter_min_tons_for_storage = minter_min_tons_for_storage
        self.discover_gas_consumption = discover_gas_consumption

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return cls(
            bridge_burn_fee=cell_slice.load_coins(),
            bridge_mint_fee=cell_slice.load_coins(),
            wallet_min_tons_for_storage=cell_slice.load_coins(),
            wallet_gas_consumption=cell_slice.load_coins(),
            minter_min_tons_for_storage=cell_slice.load_coins(),
            discover_gas_consumption=cell_slice.load_coins(),
        )


class JettonBridgeParams(TlbScheme):
    """
    jetton_bridge_params_v0#00 bridge_address:bits256 oracles_address:bits256 oracles:(HashmapE 256 uint256) state_flags:uint8 burn_bridge_fee:Coins = JettonBridgeParams;
    jetton_bridge_params_v1#01 bridge_address:bits256 oracles_address:bits256 oracles:(HashmapE 256 uint256) state_flags:uint8 prices:^JettonBridgePrices external_chain_address:bits256 = JettonBridgeParams;
    """
    def __init__(self,
                 type_: typing_extensions.Literal["jetton_bridge_params_v0", "jetton_bridge_params_v1"],
                 bridge_address: bytes,
                 oracles_address: bytes,
                 oracles: dict,
                 state_flags: int,
                 burn_bridge_fee: typing.Optional[int] = None,
                 prices: typing.Optional[JettonBridgePrices] = None,
                 external_chain_address: typing.Optional[bytes] = None,

                 ):
        self.bridge_address = bridge_address
        self.bridge_address_hex = bridge_address.hex()
        self.oracles_address = oracles_address
        self.oracles_address_hex = oracles_address.hex()
        self.oracles = oracles
        self.state_flags = state_flags
        self.burn_bridge_fee = burn_bridge_fee
        self.prices = prices
        self.external_chain_address = external_chain_address
        if external_chain_address:
            self.external_chain_address_hex = external_chain_address.hex()

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        tag = cell_slice.load_bytes(1)[:1]
        if tag not in (b'\x00', b'\x01'):
            raise ConfigError(f'JettonBridgeParams deserialization error: unexpected prefix tag {tag}')
        bridge_address = cell_slice.load_bytes(32)
        oracles_address = cell_slice.load_bytes(32)
        oracles = cell_slice.load_dict(256, value_deserializer=lambda src: src.load_uint(256))
        state_flags = cell_slice.load_uint(8)
        burn_bridge_fee = None
        prices = None
        if tag == b'\x00':
            type_ = 'jetton_bridge_params_v0'
            burn_bridge_fee = cell_slice.load_coins()
        else:
            type_ = 'jetton_bridge_params_v1'
            prices = JettonBridgePrices.deserialize(cell_slice.load_ref().begin_parse())
        return cls(
            type_=type_,
            bridge_address=bridge_address,
            oracles_address=oracles_address,
            oracles=oracles,
            state_flags=state_flags,
            burn_bridge_fee=burn_bridge_fee,
            prices=prices
        )


class ConfigParam79(JettonBridgeParams):
    """
    _ JettonBridgeParams = ConfigParam 79; // ETH->TON token bridge
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class ConfigParam81(JettonBridgeParams):
    """
    _ JettonBridgeParams = ConfigParam 81; // BNB->TON token bridge
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class ConfigParam82(JettonBridgeParams):
    """
    _ JettonBridgeParams = ConfigParam 82; // Polygon->TON token bridge
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, cell_slice: Slice):
        return super().deserialize(cell_slice)


class ConfigParam(TlbScheme):

    params = {
        0: ConfigParam0,
        1: ConfigParam1,
        2: ConfigParam2,
        3: ConfigParam3,
        4: ConfigParam4,
        5: ConfigParam5,
        6: ConfigParam6,
        7: ConfigParam7,
        8: ConfigParam8,
        9: ConfigParam9,
        10: ConfigParam10,
        11: ConfigParam11,
        12: ConfigParam12,
        13: ConfigParam13,
        14: ConfigParam14,
        15: ConfigParam15,
        16: ConfigParam16,
        17: ConfigParam17,
        18: ConfigParam18,
        20: ConfigParam20,
        21: ConfigParam21,
        22: ConfigParam22,
        23: ConfigParam23,
        24: ConfigParam24,
        25: ConfigParam25,
        28: ConfigParam28,
        29: ConfigParam29,
        31: ConfigParam31,
        32: ConfigParam32,
        33: ConfigParam33,
        34: ConfigParam34,
        35: ConfigParam35,
        36: ConfigParam36,
        37: ConfigParam37,
        44: ConfigParam44,
        71: ConfigParam71,
        72: ConfigParam72,
        73: ConfigParam73,
        79: ConfigParam79,
        81: ConfigParam81,
        82: ConfigParam82
    }

    @classmethod
    def serialize(cls, *args):
        ...

    @classmethod
    def deserialize(cls, *args):
        pass
