from dataclasses import astuple, fields

from skale.skale_manager import SkaleManager
from skale.types.schain import SchainName
from skale.utils.helper import schain_name_to_hash
from tests.constants import (
    DEFAULT_SCHAIN_HASH,
    EMPTY_SCHAIN_ARR,
    MIN_NODES_IN_SCHAIN,
    SCHAIN_FIELDS,
)


def test_get_raw(skale):
    schain = skale.schains_internal.get_raw(DEFAULT_SCHAIN_HASH)
    assert len(SCHAIN_FIELDS) == len(fields(schain)) + 2  # +2 for chainId + options


def test_get_raw_not_exist(skale):
    not_exist_schain_id = schain_name_to_hash('unused_hash')
    schain_arr = skale.schains_internal.get_raw(not_exist_schain_id)
    assert list(astuple(schain_arr)) == EMPTY_SCHAIN_ARR


def test_number_of_schains(skale: SkaleManager, schain):
    assert skale.schains_internal.number_of_schains() == 1


def test_schain_list_size(skale: SkaleManager, schain, empty_account):
    list_size = skale.schains_internal.schain_list_size(skale.wallet.address)
    empty_list_size = skale.schains_internal.schain_list_size(empty_account.address)

    assert list_size != 0
    assert empty_list_size == 0


def test_schain_hash_by_index_for_owner(skale: SkaleManager, schain):
    schain_id = skale.schains_internal.schain_hash_by_index_for_owner(skale.wallet.address, 0)
    schain = skale.schains.get(schain_id)
    assert schain.mainnet_owner == skale.wallet.address


def test_node_ids_for_schain(skale: SkaleManager, schain):
    schain_node_ids = skale.schains_internal.node_ids_for_schain(schain)

    assert isinstance(schain_node_ids, list)
    assert len(schain_node_ids) >= MIN_NODES_IN_SCHAIN


def test_schain_hashes_for_node(skale: SkaleManager, nodes, schain):
    node_id = nodes[0]
    schain_hashes_for_node = skale.schains_internal.schain_hashes_for_node(node_id)

    assert isinstance(schain_hashes_for_node, list)
    assert len(schain_hashes_for_node) > 0


def test_is_schain_exist(skale: SkaleManager, schain):
    assert skale.schains_internal.is_schain_exist(schain)
    nonexistent_chain_name = SchainName('sfdgodifjgodsaf')
    assert not skale.schains_internal.is_schain_exist(nonexistent_chain_name)


def test_get_active_schain_hashes(skale: SkaleManager, nodes, schain):
    node_id = nodes[0]
    active_schains = skale.schains_internal.active_schain_hashes_for_node(node_id)

    assert isinstance(active_schains, list)
    assert len(active_schains) > 0


def test_connected_node_ids(skale: SkaleManager, nodes, schain):
    node_id = nodes[0]
    node_ids = skale.schains_internal.connected_node_ids(node_id)
    assert isinstance(node_ids, list)
    assert len(node_ids) >= 1


def test_get_current_generation(skale):
    current_generation = skale.schains_internal.current_generation()
    assert isinstance(current_generation, int)


def test_generation_manager_role(skale):
    test_address = skale.web3.eth.account.create().address
    role = skale.schains_internal.generation_manager_role()
    assert not skale.schains_internal.has_role(role, test_address)
    skale.schains_internal.grant_role(role, test_address)
    assert skale.schains_internal.has_role(role, test_address)


def test_new_generation(skale):
    current_generation = skale.schains_internal.current_generation()
    skale.schains_internal.new_generation()
    new_generation = skale.schains_internal.current_generation()
    assert current_generation + 1 == new_generation
