"""A web3.py Contract class for the StructsC contract.

DO NOT EDIT.  This file was generated by pypechain.  See documentation at
https://github.com/delvtech/pypechain"""

# contracts have PascalCase names
# pylint: disable=invalid-name

# contracts control how many attributes and arguments we have in generated code
# pylint: disable=too-many-instance-attributes
# pylint: disable=too-many-arguments

# we don't need else statement if the other conditionals all have return,
# but it's easier to generate
# pylint: disable=no-else-return

# This file is bound to get very long depending on contract sizes.
# pylint: disable=too-many-lines

# methods are overriden with specific arguments instead of generic *args, **kwargs
# pylint: disable=arguments-differ

# consumers have too many opinions on line length
# pylint: disable=line-too-long


from __future__ import annotations

from typing import Any, Type, cast

from eth_account.signers.local import LocalAccount
from eth_typing import ABI, ChecksumAddress, HexStr
from hexbytes import HexBytes
from typing_extensions import Self
from web3 import Web3
from web3.contract.contract import Contract, ContractConstructor, ContractFunction, ContractFunctions
from web3.types import BlockIdentifier, StateOverride, TxParams

from .IStructsTypes import InnerStruct
from .StructsCTypes import CStruct, InnyStruct, NestedStruct, OuterStruct
from .utilities import rename_returned_types

structs = {
    "InnyStruct": InnyStruct,
    "NestedStruct": NestedStruct,
    "OuterStruct": OuterStruct,
    "InnerStruct": InnerStruct,
    "CStruct": CStruct,
}


class StructsCAllStructsInternalContractFunction(ContractFunction):
    """ContractFunction for the allStructsInternal method."""

    def __call__(self) -> StructsCAllStructsInternalContractFunction:  # type: ignore
        clone = super().__call__()
        self.kwargs = clone.kwargs
        self.args = clone.args
        return self

    def call(
        self,
        transaction: TxParams | None = None,
        block_identifier: BlockIdentifier = "latest",
        state_override: StateOverride | None = None,
        ccip_read_enabled: bool | None = None,
    ) -> OuterStruct:
        """returns OuterStruct."""
        # Define the expected return types from the smart contract call

        return_types = OuterStruct

        # Call the function

        raw_values = super().call(transaction, block_identifier, state_override, ccip_read_enabled)
        return cast(OuterStruct, rename_returned_types(structs, return_types, raw_values))


class StructsCInnerStructIsExternalContractFunction(ContractFunction):
    """ContractFunction for the innerStructIsExternal method."""

    def __call__(self) -> StructsCInnerStructIsExternalContractFunction:  # type: ignore
        clone = super().__call__()
        self.kwargs = clone.kwargs
        self.args = clone.args
        return self

    def call(
        self,
        transaction: TxParams | None = None,
        block_identifier: BlockIdentifier = "latest",
        state_override: StateOverride | None = None,
        ccip_read_enabled: bool | None = None,
    ) -> CStruct:
        """returns CStruct."""
        # Define the expected return types from the smart contract call

        return_types = CStruct

        # Call the function

        raw_values = super().call(transaction, block_identifier, state_override, ccip_read_enabled)
        return cast(CStruct, rename_returned_types(structs, return_types, raw_values))


class StructsCContractFunctions(ContractFunctions):
    """ContractFunctions for the StructsC contract."""

    allStructsInternal: StructsCAllStructsInternalContractFunction

    innerStructIsExternal: StructsCInnerStructIsExternalContractFunction

    def __init__(
        self,
        abi: ABI,
        w3: "Web3",
        address: ChecksumAddress | None = None,
        decode_tuples: bool | None = False,
    ) -> None:
        super().__init__(abi, w3, address, decode_tuples)
        self.allStructsInternal = StructsCAllStructsInternalContractFunction.factory(
            "allStructsInternal",
            w3=w3,
            contract_abi=abi,
            address=address,
            decode_tuples=decode_tuples,
            abi_element_identifier="allStructsInternal",
        )
        self.innerStructIsExternal = StructsCInnerStructIsExternalContractFunction.factory(
            "innerStructIsExternal",
            w3=w3,
            contract_abi=abi,
            address=address,
            decode_tuples=decode_tuples,
            abi_element_identifier="innerStructIsExternal",
        )


structsc_abi: ABI = cast(
    ABI,
    [
        {
            "type": "function",
            "name": "allStructsInternal",
            "inputs": [],
            "outputs": [
                {
                    "name": "",
                    "type": "tuple",
                    "internalType": "struct StructsC.OuterStruct",
                    "components": [
                        {
                            "name": "nested",
                            "type": "tuple",
                            "internalType": "struct StructsC.NestedStruct",
                            "components": [
                                {
                                    "name": "inner",
                                    "type": "tuple",
                                    "internalType": "struct StructsC.InnyStruct",
                                    "components": [{"name": "innerVal", "type": "uint256", "internalType": "uint256"}],
                                }
                            ],
                        }
                    ],
                }
            ],
            "stateMutability": "pure",
        },
        {
            "type": "function",
            "name": "innerStructIsExternal",
            "inputs": [],
            "outputs": [
                {
                    "name": "",
                    "type": "tuple",
                    "internalType": "struct StructsC.CStruct",
                    "components": [
                        {
                            "name": "inner",
                            "type": "tuple",
                            "internalType": "struct IStructs.InnerStruct",
                            "components": [{"name": "boolVal", "type": "bool", "internalType": "bool"}],
                        }
                    ],
                }
            ],
            "stateMutability": "pure",
        },
    ],
)


class StructsCContract(Contract):
    """A web3.py Contract class for the StructsC contract."""

    abi: ABI = structsc_abi
    # We change `bytecode` as needed for linking, but keep
    # `_raw_bytecode` unchanged as an original copy.
    # pylint: disable=line-too-long
    _raw_bytecode: HexStr | None = HexStr(
        "0x608060405234801561001057600080fd5b5060f48061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80638012d826146037578063fc0db1de14606c575b600080fd5b604080518082018252600060208083018281529092528251808401845280830182815290529151918252015b60405180910390f35b608e60408051606081018252600091810191825260208101918252908152609e565b6040519051515181526020016063565b50604080516060810182526001918101918252602081019182529081529056fea2646970667358221220a897fe982f8c33895641b65745ff946b07724c9d9115b63b8c097c9d855b260464736f6c63430008160033"
    )

    def __init__(self, address: ChecksumAddress | None = None) -> None:
        # Initialize parent Contract class
        super().__init__(address=address)
        self.functions = StructsCContractFunctions(structsc_abi, self.w3, address)  # type: ignore

    functions: StructsCContractFunctions

    @classmethod
    def constructor(cls) -> ContractConstructor:  # type: ignore
        """Creates a transaction with the contract's constructor function.

        Parameters
        ----------

        w3 : Web3
            A web3 instance.
        account : LocalAccount
            The account to use to deploy the contract.

        Returns
        -------
        Self
            A deployed instance of the contract.

        """
        cls.bytecode = cls._raw_bytecode
        if cls.bytecode is not None:

            # bytecode needs to be in hex for web3
            cls.bytecode = HexBytes(cls.bytecode)

        return super().constructor()

    @classmethod
    def deploy(cls, w3: Web3, account: LocalAccount | ChecksumAddress) -> Self:
        """Deploys an instance of the contract.

        Parameters
        ----------
        w3 : Web3
            A web3 instance.
        account : LocalAccount
            The account to use to deploy the contract.

        Returns
        -------
        Self
            A deployed instance of the contract.
        """
        deployer = cls.factory(w3=w3)
        constructor_fn = deployer.constructor()

        # if an address is supplied, try to use a web3 default account
        if isinstance(account, str):
            tx_hash = constructor_fn.transact({"from": account})
            tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)

            deployed_contract = deployer(address=tx_receipt.contractAddress)  # type: ignore
            return deployed_contract

        # otherwise use the account provided.
        deployment_tx = constructor_fn.build_transaction()
        current_nonce = w3.eth.get_transaction_count(account.address, "pending")
        deployment_tx.update({"nonce": current_nonce})

        # Sign the transaction with local account private key
        signed_tx = account.sign_transaction(deployment_tx)

        # Send the signed transaction and wait for receipt
        tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
        tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)

        deployed_contract = deployer(address=tx_receipt.contractAddress)  # type: ignore
        return deployed_contract

    @classmethod
    def factory(cls, w3: Web3, class_name: str | None = None, **kwargs: Any) -> Type[Self]:
        """Initializes the contract object.

        Parameters
        ----------
        w3 : Web3
            A web3 instance.
        class_name: str | None
            The instance class name.

        Returns
        -------
        Self
            An instance of the contract class.
        """
        contract = super().factory(w3, class_name, **kwargs)
        contract.functions = StructsCContractFunctions(structsc_abi, w3, None)

        return contract
