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

DO NOT EDIT.  This file was generated by pypechain v0.0.39.
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, NamedTuple, 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 pypechain.core import dataclass_to_tuple, rename_returned_types

from .ConstructorWithStructArgsTypes import Config, Items

structs = {
    "Items": Items,
    "Config": Config,
}


class ConstructorWithStructArgsNameContractFunction(ContractFunction):
    """ContractFunction for the name method."""

    def __call__(self) -> ConstructorWithStructArgsNameContractFunction:  # 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,
    ) -> str:
        """returns str."""
        # Define the expected return types from the smart contract call

        return_types = str

        # Call the function

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


class ConstructorWithStructArgsSetNameContractFunction(ContractFunction):
    """ContractFunction for the setName method."""

    def __call__(self, name: str) -> ConstructorWithStructArgsSetNameContractFunction:  # type: ignore
        clone = super().__call__(dataclass_to_tuple(name))
        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,
    ) -> None:
        """returns None."""
        # Define the expected return types from the smart contract call

        # Call the function


class ConstructorWithStructArgsThingContractFunction(ContractFunction):
    """ContractFunction for the thing method."""

    def __call__(self) -> ConstructorWithStructArgsThingContractFunction:  # 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,
    ) -> str:
        """returns str."""
        # Define the expected return types from the smart contract call

        return_types = str

        # Call the function

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


class ConstructorWithStructArgsContractFunctions(ContractFunctions):
    """ContractFunctions for the ConstructorWithStructArgs contract."""

    name: ConstructorWithStructArgsNameContractFunction

    setName: ConstructorWithStructArgsSetNameContractFunction

    thing: ConstructorWithStructArgsThingContractFunction

    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.name = ConstructorWithStructArgsNameContractFunction.factory(
            "name",
            w3=w3,
            contract_abi=abi,
            address=address,
            decode_tuples=decode_tuples,
            abi_element_identifier="name",
        )
        self.setName = ConstructorWithStructArgsSetNameContractFunction.factory(
            "setName",
            w3=w3,
            contract_abi=abi,
            address=address,
            decode_tuples=decode_tuples,
            abi_element_identifier="setName",
        )
        self.thing = ConstructorWithStructArgsThingContractFunction.factory(
            "thing",
            w3=w3,
            contract_abi=abi,
            address=address,
            decode_tuples=decode_tuples,
            abi_element_identifier="thing",
        )


constructorwithstructargs_abi: ABI = cast(
    ABI,
    [
        {
            "type": "constructor",
            "inputs": [
                {
                    "name": "config",
                    "type": "tuple",
                    "internalType": "struct ConstructorWithStructArgs.Config",
                    "components": [
                        {"name": "name", "type": "string", "internalType": "string"},
                        {
                            "name": "items",
                            "type": "tuple",
                            "internalType": "struct ConstructorWithStructArgs.Items",
                            "components": [
                                {"name": "thing", "type": "string", "internalType": "string"},
                                {"name": "yesOrNo", "type": "bool", "internalType": "bool"},
                            ],
                        },
                    ],
                }
            ],
            "stateMutability": "nonpayable",
        },
        {
            "type": "function",
            "name": "name",
            "inputs": [],
            "outputs": [{"name": "", "type": "string", "internalType": "string"}],
            "stateMutability": "view",
        },
        {
            "type": "function",
            "name": "setName",
            "inputs": [{"name": "_name", "type": "string", "internalType": "string"}],
            "outputs": [],
            "stateMutability": "nonpayable",
        },
        {
            "type": "function",
            "name": "thing",
            "inputs": [],
            "outputs": [{"name": "", "type": "string", "internalType": "string"}],
            "stateMutability": "view",
        },
    ],
)


class ConstructorWithStructArgsContract(Contract):
    """A web3.py Contract class for the ConstructorWithStructArgs contract."""

    abi: ABI = constructorwithstructargs_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(
        "0x60806040526002805460ff1916905534801561001a57600080fd5b506040516107673803806107678339810160408190526100399161016d565b805160009061004890826102d6565b5060208101515160019061005c90826102d6565b5060209081015101516002805460ff1916911515919091179055610395565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156100b3576100b361007b565b60405290565b604051601f8201601f191681016001600160401b03811182821017156100e1576100e161007b565b604052919050565b600082601f8301126100fa57600080fd5b81516001600160401b038111156101135761011361007b565b6020610127601f8301601f191682016100b9565b828152858284870101111561013b57600080fd5b60005b8381101561015957858101830151828201840152820161013e565b506000928101909101919091529392505050565b60006020828403121561017f57600080fd5b81516001600160401b038082111561019657600080fd5b90830190604082860312156101aa57600080fd5b6101b2610091565b8251828111156101c157600080fd5b6101cd878286016100e9565b8252506020830151828111156101e257600080fd5b9290920191604083870312156101f757600080fd5b6101ff610091565b83518381111561020e57600080fd5b61021a888287016100e9565b82525060208401519350831515841461023257600080fd5b8360208201528060208301525080935050505092915050565b600181811c9082168061025f57607f821691505b60208210810361027f57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156102d1576000816000526020600020601f850160051c810160208610156102ae5750805b601f850160051c820191505b818110156102cd578281556001016102ba565b5050505b505050565b81516001600160401b038111156102ef576102ef61007b565b610303816102fd845461024b565b84610285565b602080601f83116001811461033857600084156103205750858301515b600019600386901b1c1916600185901b1785556102cd565b600085815260208120601f198616915b8281101561036757888601518255948401946001909101908401610348565b50858210156103855787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6103c3806103a46000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806306fdde0314610046578063c47f002714610064578063c55e90fe14610079575b600080fd5b61004e610081565b60405161005b919061012c565b60405180910390f35b610077610072366004610191565b61010f565b005b61004e61011f565b6000805461008e90610242565b80601f01602080910402602001604051908101604052809291908181526020018280546100ba90610242565b80156101075780601f106100dc57610100808354040283529160200191610107565b820191906000526020600020905b8154815290600101906020018083116100ea57829003601f168201915b505050505081565b600061011b82826102cd565b5050565b6001805461008e90610242565b60006020808352835180602085015260005b8181101561015a5785810183015185820160400152820161013e565b506000604082860101526040601f19601f8301168501019250505092915050565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156101a357600080fd5b813567ffffffffffffffff808211156101bb57600080fd5b818401915084601f8301126101cf57600080fd5b8135818111156101e1576101e161017b565b604051601f8201601f19908116603f011681019083821181831017156102095761020961017b565b8160405282815287602084870101111561022257600080fd5b826020860160208301376000928101602001929092525095945050505050565b600181811c9082168061025657607f821691505b60208210810361027657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156102c8576000816000526020600020601f850160051c810160208610156102a55750805b601f850160051c820191505b818110156102c4578281556001016102b1565b5050505b505050565b815167ffffffffffffffff8111156102e7576102e761017b565b6102fb816102f58454610242565b8461027c565b602080601f83116001811461033057600084156103185750858301515b600019600386901b1c1916600185901b1785556102c4565b600085815260208120601f198616915b8281101561035f57888601518255948401946001909101908401610340565b508582101561037d5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220fb50b7afb6125dd2706f2243bf1b2b3f463ade0f1235b0bc5839d97b95a021c764736f6c63430008160033"
    )

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

    functions: ConstructorWithStructArgsContractFunctions

    class ConstructorArgs(NamedTuple):
        """Arguments to pass the contract's constructor function."""

        config: Config

    @classmethod
    def constructor(cls, config: Config) -> 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(dataclass_to_tuple(config))

    @classmethod
    def deploy(cls, w3: Web3, account: LocalAccount | ChecksumAddress, constructor_args: ConstructorArgs) -> 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(
            *constructor_args,
        )

        # 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 = ConstructorWithStructArgsContractFunctions(constructorwithstructargs_abi, w3, None)

        return contract
